package its_models.expert_model;

import its_models.expert_model.expert_help_util.StrategyGraphUnit;
import its_models.expert_model.expert_help_util.PossiblePairs;
import its_models.expert_model.expert_help_util.StepsMatrix;
import its_models.expert_model.expert_help_util.SudokuCoordinate;
import java.util.ArrayList;
import model_controller.ControlLayer;
import sudoku_gui.SudokuComponentsProperties;
import sudoku_properties.BasicSudokuParam;
import sudoku_properties.SudokuGameInfoParam;

public class LogicalRulesExpert {

    // 20091017 phrase2 start
    public LogicalRulesExpert(){
        this.Controller = new ControlLayer();
        /* this constructor is only used when the new object need to copy other */
        this.gameDifficulty = UNKNOWN;
        this.numGivenCells = DEFAULT_VALUE;
        this.strategyGraph = new StrategyGraphUnit[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInRow = new int[NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInCol = new int[NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInBox = new int[NUM_CELLS_IN_UNIT];

        //rulesRanking = new ArrayList<Integer> ();
        /* default rules ranking */
        /*for(int i=0; i<LOGICAL_RULES.length; i++){
            rulesRanking.add(i);
        }*/

        /* define gameboard information variables */
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j++){
                this.strategyGraph[i][j] = new StrategyGraphUnit(i, j);
            }
            this.numDefiniteValueInRow[i] = DEFAULT_VALUE;
            this.numDefiniteValueInCol[i] = DEFAULT_VALUE;
            this.numDefiniteValueInBox[i] = DEFAULT_VALUE;
        }
        // 20091019 phrase 2 satrt - change breadthSteps to SkillsMatrix
        this.stepsMatrix = new StepsMatrix(this.Controller);
        // 20091019 phrase 2 end
    }
    // 20091017 phrase2 end

    public LogicalRulesExpert(ControlLayer inputController){
        this.Controller = inputController;
        this.gameDifficulty = UNKNOWN;
        this.numGivenCells = DEFAULT_VALUE;
        this.strategyGraph = new StrategyGraphUnit[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInRow = new int[NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInCol = new int[NUM_CELLS_IN_UNIT];
        this.numDefiniteValueInBox = new int[NUM_CELLS_IN_UNIT];

        //rulesRanking = new ArrayList<Integer> ();
        /* default rules ranking */
        /*for(int i=0; i<LOGICAL_RULES.length; i++){
            rulesRanking.add(i);
        }*/

        /* define gameboard information variables */
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j++){
                this.strategyGraph[i][j] = new StrategyGraphUnit(i, j);
            }
            this.numDefiniteValueInRow[i] = DEFAULT_VALUE;
            this.numDefiniteValueInCol[i] = DEFAULT_VALUE;
            this.numDefiniteValueInBox[i] = DEFAULT_VALUE;
        }

        // 20091019 phrase 2 satrt - change breadthSteps to SkillsMatrix
        this.stepsMatrix = new StepsMatrix(this.Controller);
        // 20091019 phrase 2 end
    }

    // 20091017 phrase2 start
    /* update logical rule, when one or more used */
    public void addARule(int indexX, int indexY, String logicalRuleAdd){
        String logicalRule = this.strategyGraph[indexX][indexY].getLogicalRule() + " / "+ logicalRuleAdd;
        this.strategyGraph[indexX][indexY].setLogicalRule(logicalRule);
    }
    /* Rules Ranking */
    /*public void setRulesRanking(ArrayList<Integer> inputRulesRanking){
        rulesRanking.clear();
        rulesRanking = inputRulesRanking ;
    }*/
    /* Pretend to be the copy constructor */
    //public LogicalRulesExpert(LogicalRulesExpert copyedLRE){
    // 20091029 phrase 2 start
    public void copy(LogicalRulesExpert copyedLRE){
        this.Controller = copyedLRE.getController();
        this.gameDifficulty = copyedLRE.getGameDifficulty();
        this.numGivenCells = copyedLRE.getNumGivenCells();
        this.strategyGraph = new StrategyGraphUnit[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT];
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j++){
                this.strategyGraph[i][j] = new StrategyGraphUnit(i, j);
                this.strategyGraph[i][j].copy(copyedLRE.strategyGraph[i][j]);
            }
            this.numDefiniteValueInRow[i] = copyedLRE.getnumDefiniteValueInRow(i);
            this.numDefiniteValueInCol[i] = copyedLRE.getnumDefiniteValueInCol(i);
            this.numDefiniteValueInBox[i] = copyedLRE.getnumDefiniteValueInBox(i);
        }
        /*this.rulesRanking = copyedLRE.getRulesRanking();*/
        // 20091019 phrase 2 satrt - change breadthSteps to SkillsMatrix
        //this.stepsMatrix = copyedLRE.getStepsMatrix();
        this.stepsMatrix =new StepsMatrix(this.Controller);
        // 20091019 phrase 2 end
    }
    // 20091029 phrase 2 end

    /* Only for the copy constructor start */
    public String getGameDifficulty(){
        return this.gameDifficulty;
    }
    private int getNumGivenCells(){
        return this.numGivenCells;
    }
    private StrategyGraphUnit[][] getCellValuePossibility(){
        return this.strategyGraph;
    }
    private int getnumDefiniteValueInRow(int index){
        return this.numDefiniteValueInRow[index];
    }
    private int getnumDefiniteValueInCol(int index){
        return this.numDefiniteValueInCol[index];
    }
    private int getnumDefiniteValueInBox(int index){
        return this.numDefiniteValueInBox[index];
    }
    /*private ArrayList<Integer> getRulesRanking(){
        return this.rulesRanking;
    }*/
    private StepsMatrix getStepsMatrix(){
        // 20091019 phrase 2 satrt - change breadthSteps to SkillsMatrix
        return this.stepsMatrix;
        // 20091019 phrase 2 end
    }
    private ControlLayer getController(){
        return this.Controller;
    }
    /* Only for the copy constructor end */
    // 20091017 phrase2 end

    /* Cells Given Information */
    public void setNumGivenCells(int inputNumGivenCells){
        this.numGivenCells = inputNumGivenCells;
    }

    /* Difficulty */
    public void setDifficultyLevel(String inputDifficultyLevel){
        this.gameDifficulty = inputDifficultyLevel;
    }
    /* return the range of cells given according to game difficult */
    public Integer[] getDifficultyRange(int inputDifficultyLevel){
        final int difficultLevel = inputDifficultyLevel;
        /* 0 is min, 1 is max range */
        Integer[] rangeOfGivenCell = SudokuGameInfoParam.getDifficultyRange(difficultLevel) ;
        return rangeOfGivenCell;
    }

    /* return Number of Cells unSolved*/
    public int getNumCellsUnsolved(){
        int unsolvedCounter = 0;
        for(int i=0; i<this.strategyGraph.length; i++){
            for(int j=0; j<this.strategyGraph[i].length; j++){
                if(!this.strategyGraph[i][j].getDefiniteValueSet()){
                    unsolvedCounter++;
                }
            }
        }
        return unsolvedCounter;
    }

    /* return value(s) involved in using a rule*/
     public int[] getValueInvolved(StrategyGraphUnit involvedCell){
        int indexX = involvedCell.getColumnIndex();
        int indexY = involvedCell.getRowIndex();
        int[] involvedValue = null;
        if(involvedCell.getPurposeOfLastLogicalRule().equalsIgnoreCase(ExpertModelProperties.getDefineIndicator())){
            /* only one involvedValue for definite cell */
            involvedValue = new int[1];
            involvedValue[0] = involvedCell.getDefiniteValue();
        }else if(involvedCell.getPurposeOfLastLogicalRule().equalsIgnoreCase(ExpertModelProperties.getEliminateIndicator())){
            involvedValue = this.strategyGraph[indexX][indexY].getPossValuesNotIn(involvedCell);
        }   
        return involvedValue;
    }

    /* Cell Possibility */
    public void setGivenCellDefiniteValue(int inputIndexX, int inputIndexY, int inputCellValue){
        /* logical rules, effictive scope and pupose of rules applied is NA */
        // 20091018 phrase2 start  - change NA to unknown
        final String logicalRule = UNKNOWN;
        final String effectiveScope = UNKNOWN;
        final String purposeOfRulesApplied = DEFINE_INDICATOR;
        this.setCellDefiniteValue(inputIndexX, inputIndexY, inputCellValue,
                logicalRule, effectiveScope, purposeOfRulesApplied);
    }

    public void setCellDefiniteValue(int inputIndexX, int inputIndexY, int inputCellValue,
            String inputLogicalRule, String inputEffectiveScope, String inputPurposeOfRuleApplied){

        final int colIndex = inputIndexX;
        final int rowIndex = inputIndexY;
        final int boxIndex = this.strategyGraph[colIndex][rowIndex].getBoxIndex();
        final int cellValue = inputCellValue;
        final String logicalRules = inputLogicalRule;
        final String effectiveScope = inputEffectiveScope;
        final String purposeOfRuleApplied  =inputPurposeOfRuleApplied;

        /* Step 1 : set cell Possibility */
        this.strategyGraph[colIndex][rowIndex].setDefiniteValue(cellValue, logicalRules, effectiveScope, purposeOfRuleApplied);

        /* Step 2 : update the number of definite value in scope */
        this.addDefiniteValueInScope(colIndex, rowIndex, boxIndex);

        /* Step 3 : eliminate impossible cellvalue to same scope of cell */
        this.setImpossValueToCellWithSameScope(colIndex, rowIndex, boxIndex, cellValue);
    }
    public void setCellDefiniteValue(int inputIndexX, int inputIndexY, int inputCellValue){

        final int colIndex = inputIndexX;
        final int rowIndex = inputIndexY;
        final int boxIndex = strategyGraph[colIndex][rowIndex].getBoxIndex();
        final int cellValue = inputCellValue;
        // 20091018 phrase2 start  - change NA to unknown
        String logicalRule = UNKNOWN;
        String effectiveScope = UNKNOWN;
        // 20091018 phrase2 end
        String purposeOfRuleApplied = DEFINE_INDICATOR;
        boolean isCellFound = false;

        // 20091019 phrase2 start - change breadthSteps to SkillMatrix
        for(int i=0; i<this.stepsMatrix.getBreadthStepsLength() && !isCellFound; i++){
            for(int j=0; j<this.stepsMatrix.getBreadthStepsFoundOnRule(i).size() && !isCellFound; j++){
                if( (this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getColumnIndex() == colIndex)
                    && (this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getRowIndex() == rowIndex) ){
                    logicalRule = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getLogicalRule();
                    effectiveScope = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getScopeEffectiveIn();
                    purposeOfRuleApplied = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getPurposeOfLastLogicalRule();
                    isCellFound = true;
                }
            }
        }
         // 20091019 phrase2 end

        /* Step 1 : set cell Possibility */
        this.strategyGraph[colIndex][rowIndex].setDefiniteValue(cellValue, logicalRule, effectiveScope, purposeOfRuleApplied);

        /* Step 2 : update the number of definite value in scope */
        this.addDefiniteValueInScope(colIndex, rowIndex, boxIndex);

        /* Step 3 : eliminate impossible cellvalue to same scope of cell */
        this.setImpossValueToCellWithSameScope(colIndex, rowIndex, boxIndex, cellValue);
    }
    public boolean getDefiniteValueSet(int inputIndexX, int inputIndexY){
        return this.strategyGraph[inputIndexX][inputIndexY].getDefiniteValueSet();
    }

    // 20091017 phrase2 start
    public String getRuleUsed(int inputIndexX, int inputIndexY){
        return this.strategyGraph[inputIndexX][inputIndexY].getLogicalRule();
    }
    public void setRuleUsed(int inputIndexX,int inputIndexY, String rule){
        this.strategyGraph[inputIndexX][inputIndexY].setLogicalRule(rule);
    }
    // 20091017 phrase2 end
    public void removeDefiniteValue(int inputIndexX, int inputIndexY){
        final int indexX = inputIndexX;
        final int indexY = inputIndexY;
        this.strategyGraph[indexX][indexY].removeDefiniteValue();
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j++){
                if(!this.strategyGraph[i][j].getDefiniteValueSet()){
                    this.strategyGraph[i][j].reset();
                }
            }
        }
        this.refreshPossValue();
    }

    public void addDefiniteValueInScope(int inputColIndex, int inputRowIndex, int inputBoxIndex){
        this.numDefiniteValueInCol[inputColIndex]++;
        this.numDefiniteValueInRow[inputRowIndex]++;
        this.numDefiniteValueInBox[inputBoxIndex]++;
    }

    public void setImpossValueToCellWithSameScope(int inputColIndex, int inputRowIndex, int inputBoxIndex, int inputCellValue){
        final int colIndex = inputColIndex;
        final int rowIndex = inputRowIndex;
        final int boxIndex = inputBoxIndex;
        final int cellValue = inputCellValue;

        for(int i=0; i<this.strategyGraph.length; i++){
            for(int j=0; j<this.strategyGraph[i].length; j++){
                /* Condition 1 : exactly the same cell */
                if ( !((this.strategyGraph[i][j].getRowIndex() == rowIndex)
                        && (this.strategyGraph[i][j].getColumnIndex() == colIndex)
                        && (this.strategyGraph[i][j].getBoxIndex() == boxIndex)) ){
                    /* Condition 2 : cells in same scope */
                    if ((this.strategyGraph[i][j].getRowIndex() == rowIndex)
                        || (this.strategyGraph[i][j].getColumnIndex() == colIndex)
                        || (this.strategyGraph[i][j].getBoxIndex() == boxIndex)){
                        /* setValue impossible */
                        this.strategyGraph[i][j].setImpossValue(cellValue);
                    }
                }
            }
        }
    }
    public void setImpossValue(int inputIndexX, int inputIndexY, int inputCellValue){
        int indexX = inputIndexX;
        int indexY = inputIndexY;
        int cellValue = inputCellValue;
        this.strategyGraph[indexX][indexY].setImpossValue(cellValue);
    }
    public void refreshPossValue(){
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            this.numDefiniteValueInRow[i] = DEFAULT_VALUE;
            this.numDefiniteValueInCol[i] = DEFAULT_VALUE;
            this.numDefiniteValueInBox[i] = DEFAULT_VALUE;
        }

        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j++){
                if(this.strategyGraph[i][j].getDefiniteValueSet()){
                    final int cellValue = this.strategyGraph[i][j].getDefiniteValue();
                    final String logicalRules = this.strategyGraph[i][j].getLogicalRule();
                    final String effectiveScope = this.strategyGraph[i][j].getScopeEffectiveIn();
                    final String purposeOfRuleApplied = this.strategyGraph[i][j].getPurposeOfLastLogicalRule();
                    final int colIndex = this.strategyGraph[i][j].getColumnIndex();
                    final int rowIndex = this.strategyGraph[i][j].getRowIndex();
                    final int boxIndex = this.strategyGraph[i][j].getBoxIndex();
                    /* Step 1 : set cell Possibility */
                    this.strategyGraph[colIndex][rowIndex].setDefiniteValue(cellValue, logicalRules, effectiveScope, purposeOfRuleApplied);
                    /* Step 2 : update the number of definite value in scope */
                    this.addDefiniteValueInScope(colIndex, rowIndex, boxIndex);
                    /* Step 3 : eliminate impossible cellvalue to same scope of cell */
                    this.setImpossValueToCellWithSameScope(colIndex, rowIndex, boxIndex, cellValue);
                }
            }
        }
    }

/* logical rules */
    public StepsMatrix applyLogicalRules(){  

        emptyBreadthStepsMatrix();        
        isSingleInGroupFound();
        isHiddenSingleFound();
        isNakedSingleFound();
        isIntersectionReductionFound();
        isNakedPairsFound();
        isHiddenPairsFound();

        return this.stepsMatrix;
    }

    /* EmptyBreadthSteps*/
    public void emptyBreadthStepsMatrix(){
        stepsMatrix.emptyBreadthSteps();
    }
    // 20091029 phrase2 start
    /* EmptyDepathSteps */
    public void empthDepthStepsMatrix(){
        stepsMatrix.empthDepthSteps();
    }
    // 20091029 phrase2 end

    /* Rule is used when */
    /* Only one remainning value in row, column or box */
    public boolean isSingleInGroupFound(){

        /* define varaialbes used */
        final int defaultIndexX = DEFAULT_VALUE;
        final int defaultIndexY = DEFAULT_VALUE;
        boolean isSingleInGroupFoundInRow = false ;
        boolean isSingleInGroupFoundInCol = false ;
        boolean isSingleInGroupFoundInBox = false ;

        /* check if apply in all Column  - take the first cell of all row */
        /* NUM_CELLS_IN_UNIT -1 indicates only one cell value is missing within the same column */
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            if( numDefiniteValueInCol[i] == (NUM_CELLS_IN_UNIT -1)){
                final int[][] sameColIndices = strategyGraph[i][defaultIndexY].getSameColumnIndices();
                final boolean isApplied = this.isSingleInGroupApplied(sameColIndices, COL_SCOPE_INDICATOR);
                isSingleInGroupFoundInCol = isSingleInGroupFoundInCol || isApplied;
            }
        }

        /* check if apply in all row  - take the first cell of all column */
        /* NUM_CELLS_IN_UNIT -1 indicates only one cell value is missing within the same row */
        for(int i=0; i<NUM_CELLS_IN_UNIT; i++){
            if( numDefiniteValueInRow[i] == (NUM_CELLS_IN_UNIT -1)){
                final int[][] sameRowIndices = strategyGraph[defaultIndexX][i].getSameRowIndices();
                final boolean isApplied = this.isSingleInGroupApplied(sameRowIndices, ROW_SCOPE_INDICATOR);
                isSingleInGroupFoundInRow = isSingleInGroupFoundInRow || isApplied;
            }
        }

        /* Check if rule act on Box */
        /* NUM_CELLS_IN_UNIT -1 indicates only one cell value is missing within the same box */
        for(int i=0; i < NUM_CELLS_IN_UNIT; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
                final int boxIndex = strategyGraph[i][j].getBoxIndex();
                if( numDefiniteValueInBox[boxIndex] == (NUM_CELLS_IN_UNIT -1)){
                    final int[][] sameBoxIndices = strategyGraph[i][j].getSameBoxIndices();
                    final boolean isApplied = isSingleInGroupApplied(sameBoxIndices, BOX_SCOPE_INDICATOR);
                    isSingleInGroupFoundInBox = isSingleInGroupFoundInBox || isApplied;
                }
            }
        }
        return ( isSingleInGroupFoundInRow || isSingleInGroupFoundInCol || isSingleInGroupFoundInBox );
    }
    public boolean isSingleInGroupApplied(int[][] inputScopeIndices, String inputScope){
        final int[][] scopeIndices = inputScopeIndices;
        final String scope = inputScope;
        boolean isSingleInGroupApplied = false;

        for( int i=0; i < scopeIndices.length ; i++){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR];
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR];
            /* only one possible value is left */
            if(!strategyGraph[indexX][indexY].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                if(strategyGraph[indexX][indexY].getNumOfPossValues() == 1){
                    /* add cell unit to arraylist */
                    StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                    solvedUnit.copy( strategyGraph[indexX][indexY], indexX, indexY) ;
                    solvedUnit.setLogicalRule(SINGLE_IN_GROUP_INDICATOR);
                    solvedUnit.setScopeEffectiveIn(scope);
                    solvedUnit.setPurposeOfLastLogicalRule(DEFINE_INDICATOR) ;
                    /* Not required to set the definite value */
                    // 20091019 phrase2 start - change breadthSteps to SkillsMatrix
                    this.stepsMatrix.getBreadthStepsFoundOnRule(SINGLE_IN_GROUP_INDEX).add(solvedUnit);
                    //breadthSteps[SINGLE_IN_GROUP_INDEX].add(solvedUnit) ;
                    // 20091019 phrase2 end
                    isSingleInGroupApplied = true ;
                    break; /* as there is only one value left */
                }
            }
        }
        return isSingleInGroupApplied;
    }

    public boolean isHiddenSingleFound(){

        final int defaultIndexX = DEFAULT_VALUE;
        final int defaultIndexY = DEFAULT_VALUE;

        boolean isHiddenSignleFoundinRow = false ;
        boolean isHiddenSignleFoundinCol = false ;
        boolean isHiddenSignleFoundinBox = false ;

        /* check if apply in all Column  - take the first cell of all row */
        for( int i= 0 ; i < NUM_CELLS_IN_UNIT; i++){
            final int[][] sameColumnIndices = strategyGraph[i][defaultIndexY].getSameColumnIndices();
            final boolean isApplied = this.isHiddenSingleApplied(sameColumnIndices, COL_SCOPE_INDICATOR);
            isHiddenSignleFoundinCol = isHiddenSignleFoundinCol || isApplied;
        }

        /* check if apply in all row - take the first cell of all column  */
        for( int i=0; i<NUM_CELLS_IN_UNIT ; i++){
            final int[][] sameRowIndices = strategyGraph[defaultIndexX][i].getSameRowIndices();
            final boolean isApplied = this.isHiddenSingleApplied(sameRowIndices, ROW_SCOPE_INDICATOR);
            isHiddenSignleFoundinRow = isHiddenSignleFoundinRow || isApplied;
        }

        /* check if apply in box */
        /* take the first cells in every box for checking */
        for(int i=0; i < NUM_CELLS_IN_UNIT; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
                final int[][] sameBoxIndices = strategyGraph[i][j].getSameBoxIndices();
                final boolean isApplied = this.isHiddenSingleApplied(sameBoxIndices, BOX_SCOPE_INDICATOR);
                isHiddenSignleFoundinBox = isHiddenSignleFoundinBox || isApplied;
            }
        }

        return ( isHiddenSignleFoundinRow || isHiddenSignleFoundinCol || isHiddenSignleFoundinBox);
    }
    public boolean isHiddenSingleApplied(int[][] inputScopeIndices, String inputScope){
        final int[][] scopeIndices = inputScopeIndices;
        final String scope = inputScope;
        boolean isHiddenSignleFound = false ;

        /* Step 1. set the array that count the number of cells valid to place the possible value */
        int[] possValuesInSameScopeCounter = new int[NUM_CELLS_IN_UNIT] ;
        for( int i=0 ; i < possValuesInSameScopeCounter.length ; i++){
            possValuesInSameScopeCounter[i] = 0 ;
        }

        /* 2. find the number of cells valid to place the possible values */
        for( int i= 0 ; i< scopeIndices.length ; i++){

            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;

            /* if cells has definite value, set the counter to -1 */
            if( strategyGraph[indexX][indexY].hasDefiniteValue()){
                final int definiteCellValueIndex = (strategyGraph[indexX][indexY].getDefiniteValue()-1) ;
                possValuesInSameScopeCounter[definiteCellValueIndex] = INACTIVE_FLAG ;
            }
            else if( !strategyGraph[indexX][indexY].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                ArrayList<Integer> possCellValue = strategyGraph[indexX][indexY].getListOfPossibleValues() ;
                /* Update Possible Value Counter */
                for( int j= 0; j < possCellValue.size() ; j++){
                    final int possCellValueIndex = ( possCellValue.get(j) - 1 ) ;
                    if(possValuesInSameScopeCounter[possCellValueIndex] != INACTIVE_FLAG ){
                        possValuesInSameScopeCounter[possCellValueIndex] ++;
                    }
                }
            }
        }

        /* Step 3 : find for Hidden Single */
        int valueRecoveredByHiddenSingle = INACTIVE_FLAG;
        for( int i = 0 ; i < possValuesInSameScopeCounter.length ; i++ ){
            if(possValuesInSameScopeCounter[i]==1 ){
                valueRecoveredByHiddenSingle = ( i+1 ) ;
                break;
            }
        }

        /* Step 4 :  add Logical Rules Found record */
        if( valueRecoveredByHiddenSingle != INACTIVE_FLAG ){
            for( int i = 0 ; i < scopeIndices.length ; i++ ){
                final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
                final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;
                if(!strategyGraph[indexX][indexY].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                    if( strategyGraph[indexX][indexY].isPossibleFor(valueRecoveredByHiddenSingle)) {
                        StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                        solvedUnit.copy(strategyGraph[indexX][indexY], indexX, indexY) ;
                        solvedUnit.setLogicalRule(HIDDEN_SINGLE_INDICATOR);
                        solvedUnit.setScopeEffectiveIn(scope);
                        solvedUnit.setPurposeOfLastLogicalRule(DEFINE_INDICATOR) ;
                        solvedUnit.setDefiniteValue(valueRecoveredByHiddenSingle);
                        // 20091019 phrase2 start - change breadthSteps to SkillsMatrix
                         this.stepsMatrix.getBreadthStepsFoundOnRule(HIDDEN_SINGLE_INDEX).add(solvedUnit);
                        // breadthSteps[HIDDEN_SINGLE_INDEX].add(solvedUnit);
                         // 20091019 phrase2 end
                        isHiddenSignleFound = true;
                        break; /* cells of ruels applied is found */
                    }
                }
            }
        }
        return isHiddenSignleFound ;
    }

    public boolean isNakedSingleFound(){
       // final int defaultIndexX = DEFAULT_VALUE;
        final int defaultIndexY = DEFAULT_VALUE;
        //boolean isNakedSingleFoundinRow = false ;
       // boolean isNakedSingleFoundinCol = false ;
       // boolean isNakedSingleFoundinBox = false ;
        boolean isNakedSingleFoundinAll = false ;
        /* check all cells  - check in column includes all cells */
        for( int i= 0 ; i < NUM_CELLS_IN_UNIT; i++){
            final int[][] sameColIndices = strategyGraph[i][defaultIndexY].getSameColumnIndices();
            final boolean isApplied = this.isNakedSingleApplied(sameColIndices, ALL_SCOPE_INDICATOR);
            /* if isNakedSingleFoundinAll is true, isApplied will not be considered to get isNakedSingleFoundinAll*/
            isNakedSingleFoundinAll = isNakedSingleFoundinAll || isApplied;
        }

        /* check if apply in Row */
        /*for( int i= 0 ; i < NUM_CELLS_IN_UNIT; i++){
            final int[][] sameRowIndices = strategyGraph[i][defaultIndexY].getSameRowIndices();
            isNakedSingleFoundinRow = this.isNakedSingleApplied(sameRowIndices, COL_SCOPE_INDICATOR);
        }*/

        /* check if apply in column */
       /* for( int i=0; i<NUM_CELLS_IN_UNIT ; i++){
            final int[][] sameColIndices = strategyGraph[defaultIndexX][i].getSameColumnIndices();
            isNakedSingleFoundinCol = this.isNakedSingleApplied(sameColIndices, ROW_SCOPE_INDICATOR);
        }*/

        /* check if apply in box */
        /* take the first cells in every box for checking */
        /*for(int i=0; i < NUM_CELLS_IN_UNIT; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
               final int[][] sameBoxIndices = strategyGraph[defaultIndexX][i].getSameBoxIndices();
               isNakedSingleFoundinBox = this.isNakedSingleApplied(sameBoxIndices, BOX_SCOPE_INDICATOR);
            }
        }*/
        //return ( isNakedSingleFoundinRow || isNakedSingleFoundinCol || isNakedSingleFoundinBox );
        return isNakedSingleFoundinAll;
    }
    public boolean isNakedSingleApplied(int[][] inputScopeIndices, String inputScope){
        final int[][] scopeIndices = inputScopeIndices;
        final String scope = inputScope;
        boolean isNakedSingleFound = false ;

        for( int i = 0 ; i < scopeIndices.length ; i++ ){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;
             if(!strategyGraph[indexX][indexY].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                if( strategyGraph[indexX][indexY].getNumOfPossValues() == 1){
                    StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                    solvedUnit.copy( strategyGraph[indexX][indexY], indexX, indexY) ;
                    solvedUnit.setLogicalRule(NAKED_SINGLE_INDICATOR);
                    solvedUnit.setScopeEffectiveIn(scope);
                    solvedUnit.setPurposeOfLastLogicalRule(DEFINE_INDICATOR) ;
                    // 20091019 phrase2 start - change breadthSteps to SkillsMatrix
                    this.stepsMatrix.getBreadthStepsFoundOnRule(NAKED_SINGLE_INDEX).add(solvedUnit);
                    // breadthSteps[NAKED_SINGLE_INDEX].add(solvedUnit);
                    // 20091019 phrase2 end
                    isNakedSingleFound = true ;
                }
            }
        }
        return isNakedSingleFound ;
    }

    public boolean isIntersectionReductionFound(){
        boolean isInterReductionFound = false ;
        /* This rules only applied in box */

        for(int i=0; i < NUM_CELLS_IN_UNIT ; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
                final int[][] sameBoxIndices = strategyGraph[i][j].getSameBoxIndices() ;
                final boolean isApplied = isIntersectionReductionApplied(sameBoxIndices);
                isInterReductionFound = isInterReductionFound || isApplied;
            }
        }
        return isInterReductionFound ;
    }
    public boolean isIntersectionReductionApplied(int[][] inputScopeIndices){
        final int[][] scopeIndices = inputScopeIndices;
        boolean isInterReductionFound = false ;

        /* an array of ArrayList of SudokuCoordinate to Find those possible position of cell values */
        ArrayList<SudokuCoordinate>[] possPositionsOfValues = new ArrayList[NUM_CELLS_IN_UNIT] ;
        /* initialize the array of SudokuCoordinate */
        for( int i = 0 ; i < possPositionsOfValues.length && !isInterReductionFound; i++ ){
            possPositionsOfValues[i] = new ArrayList<SudokuCoordinate>() ;
        }

        /* Step 1 : Store the Possible Position for all cells with same cell poss value */
        for( int i=0 ; i < scopeIndices.length ; i++){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;

            if( strategyGraph[indexX][indexY].hasDefiniteValue() ){

                final int definiteValueIndex = ( strategyGraph[indexX][indexY].getDefiniteValue() - 1 ) ;
                possPositionsOfValues[definiteValueIndex] = null;

            }
            else{
                ArrayList<Integer> possCellValue = strategyGraph[indexX][indexY].getListOfPossibleValues() ;
                for( int j = 0 ; j < possCellValue.size() ; j++ ){
                    final int possCellValueIndex = ( possCellValue.get(j) - 1 ) ;
                    if( possPositionsOfValues[possCellValueIndex] != null ){
                        SudokuCoordinate activeCoordinate = new SudokuCoordinate();
                        activeCoordinate.copy( strategyGraph[indexX][indexY].getCellCoordinate() ) ;
                        possPositionsOfValues[possCellValueIndex].add(activeCoordinate) ;
                    }
                }
            }
        }

        /* Step 2 : Check if Intersection Reduction able to applied */
        for( int i = 0; i < possPositionsOfValues.length; i++ ){
            if( possPositionsOfValues[i] != null ){

                final int numOfPossCor = possPositionsOfValues[i].size() ;
                /* Condition 1: only 2 or 3 possibile places for a value within a Box */
                if( numOfPossCor > MIN_POSS_COR_IR && numOfPossCor < MAX_POSS_COR_IR ){
                    /* Condition 2: those places are within a same Row or Column */
                    boolean isSameIndexX = true ;
                    boolean isSameIndexY = true ;

                    /* check if the poss coordinate is of same row or column */
                    /*for(int j=0; j< possPositionsOfValues[i].size()-1 ; j++){
                        boolean isTempSameIndexX =
                                (possPositionsOfValues[i].get(j).getColumnIndex() ==  possPositionsOfValues[i].get(j+1).getColumnIndex());
                        boolean isTempSameIndexY =
                                (possPositionsOfValues[i].get(j).getRowIndex() ==  possPositionsOfValues[i].get(j+1).getRowIndex());
                        isSameIndexX = isSameIndexX && isTempSameIndexX;
                        isSameIndexY = isSameIndexY && isTempSameIndexY;
                    }*/

                    int colIndex = possPositionsOfValues[i].get(0).getColumnIndex() ;
                    int rowIndex = possPositionsOfValues[i].get(0).getRowIndex() ;

                    for( int  j = 1 ;
                    (( isSameIndexX || isSameIndexY ) && ( j < possPositionsOfValues[i].size()));
                         ++j){

                        int columnIndexToCheckWith = possPositionsOfValues[i].get(j).getColumnIndex() ;
                        int rowIndexToCheckWith = possPositionsOfValues[i].get(j).getRowIndex() ;

                        isSameIndexX = isSameIndexX && (colIndex == columnIndexToCheckWith) ;
                        isSameIndexY = isSameIndexY && (rowIndex == rowIndexToCheckWith) ;

                        colIndex = columnIndexToCheckWith;
                        rowIndex = rowIndexToCheckWith; 
                    }


                    /*check if rules is apply in column */
                    if(isSameIndexX){
                        final int valueToEliminate = ( i+1 ) ;
                        /* As they must in the same box, any poss cor will result in same box index */
                        final int boxIndex = possPositionsOfValues[i].get(0).getBoxIndex() ;
                        /* Condition3a: there is place(s) for this value in the same column, but not in this box */
                        for( int j=0; j < (NUM_CELLS_IN_UNIT-1) && !isInterReductionFound; ++j ){

                            if(!strategyGraph[colIndex][j].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                                if( (strategyGraph[colIndex][j].getBoxIndex() != boxIndex)
                                        && (strategyGraph[colIndex][j].isPossibleFor(valueToEliminate)) ){

                                    StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                                    //solvedUnit.copy(strategyGraph[colIndex][rowIndex], colIndex, rowIndex);
                                    solvedUnit.copy(strategyGraph[colIndex][j], colIndex, j);
                                    solvedUnit.setLogicalRule(INTERSECT_REDUCT_INDICATOR);
                                    solvedUnit.setScopeEffectiveIn(COL_SCOPE_INDICATOR);
                                    solvedUnit.setImpossValue(valueToEliminate);
                                    solvedUnit.setPurposeOfLastLogicalRule(ELIMINATE_INDICATOR) ;
                                    // 20091019 phrase2 start - change breadthSteps to SkillsMatrix
                                    this.stepsMatrix.getBreadthStepsFoundOnRule(INTERSECT_REDUCT_INDEX).add(solvedUnit);
                                    // breadthSteps[INTERSECT_REDUCT_INDEX].add(solvedUnit);
                                    // 20091019 phrase2 end
                                    isInterReductionFound = true ;
                                }
                            }
                        }
                    }

                    /* check if rules is apply in row */
                    if(isSameIndexY){

                        final int valueToEliminate = ( i+1 ) ;
                        /* As they must in the same box, any poss cor will result in same box index */
                        final int boxIndex = possPositionsOfValues[i].get(0).getBoxIndex() ;
                        /* Condition3a: there is place(s) for this value in the same column, but not in this box */
                        for( int j=0; j < (NUM_CELLS_IN_UNIT-1); ++j ){
                            if(!strategyGraph[j][rowIndex].getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                                if( (strategyGraph[j][rowIndex].getBoxIndex() != boxIndex)
                                        && (strategyGraph[j][rowIndex].isPossibleFor(valueToEliminate)) ){
  
                                    StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                                    //solvedUnit.copy( strategyGraph[colIndex][rowIndex], colIndex, rowIndex);
                                    solvedUnit.copy( strategyGraph[j][rowIndex], j, rowIndex);
                                    solvedUnit.setLogicalRule(INTERSECT_REDUCT_INDICATOR);
                                    solvedUnit.setScopeEffectiveIn(ROW_SCOPE_INDICATOR);
                                    solvedUnit.setImpossValue(valueToEliminate);
                                    solvedUnit.setPurposeOfLastLogicalRule(ELIMINATE_INDICATOR) ;
                                    // 20091019 phrase2 start - change breadthSteps to SkillsMatrix
                                    this.stepsMatrix.getBreadthStepsFoundOnRule(INTERSECT_REDUCT_INDEX).add(solvedUnit);
                                    // breadthSteps[INTERSECT_REDUCT_INDEX].add(solvedUnit);
                                    // 20091019 phrase2 end
                                    isInterReductionFound = true ;
                                }
                            }
                        }
                    }
                }
            }
        }

        return isInterReductionFound ;
    }
    
    /* Naked Pairs : found the number of set which only contain certain set(size 2-4) digits*/
    public boolean isNakedPairsFound(){
        
        final int defaultIndexX = DEFAULT_VALUE;
        final int defaultIndexY = DEFAULT_VALUE;
        boolean isNakedPairsFoundinRow = false ;
        boolean isNakedPairsFoundinCol = false ;
        boolean isNakedPairsFoundinBox = false ;

        /* check if apply in all Column  - take the first cell of all row */
        for( int i= 0 ; i < NUM_CELLS_IN_UNIT; i++){
            final int[][] sameColumnIndices = strategyGraph[i][defaultIndexY].getSameColumnIndices();
            final boolean isApplied = this.isNakedPairsApplied(sameColumnIndices, COL_SCOPE_INDICATOR);
            isNakedPairsFoundinCol = isNakedPairsFoundinCol || isApplied;
        }

        /* check if apply in all row - take the first cell of all column  */
        for( int i=0; i<NUM_CELLS_IN_UNIT ; i++){
            final int[][] sameRowIndices = strategyGraph[defaultIndexX][i].getSameRowIndices();
            final boolean isApplied = this.isNakedPairsApplied(sameRowIndices, ROW_SCOPE_INDICATOR);
            isNakedPairsFoundinRow = isNakedPairsFoundinRow || isApplied;
        }

        /* check if apply in box */
        /* take the first cells in every box for checking */
        for(int i=0; i < NUM_CELLS_IN_UNIT; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
                final int[][] sameBoxIndices = strategyGraph[defaultIndexX][i].getSameBoxIndices();
                final boolean isApplied = this.isNakedPairsApplied(sameBoxIndices, BOX_SCOPE_INDICATOR);
                isNakedPairsFoundinBox = isNakedPairsFoundinBox || isApplied;
            }
        }

        return ( isNakedPairsFoundinRow || isNakedPairsFoundinCol || isNakedPairsFoundinBox );
    }
    public boolean isNakedPairsApplied(int[][] inputScopeIndices, String inputScope){
        final int[][] scopeIndices = inputScopeIndices;
        final String scope = inputScope;
        boolean isNakedPairsFound = false ;
        /* Step 1: check if is naked pairs */
        for( int i=0 ; i < scopeIndices.length; i++ ){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValue = strategyGraph[indexX][indexY].getListOfPossibleValues() ;
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy( strategyGraph[indexX][indexY].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValue.size()>=2 && possCellValue.size()<=4){
            //if( possCellValue.size()==2){
                for(int j=0; j<scopeIndices.length; j++){

                    final int indexXComp = scopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = scopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;

                    boolean isPairsCell = true;
                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() <= possCellValue.size() && possCellValueComp.size()>1){
                    //if( i!=j && possCellValueComp.size()==2){
                        for(int k=0; k<possCellValueComp.size(); k++){
                            int valueInvolved = possCellValueComp.get(k);
                            if(possCellValue.indexOf(valueInvolved)==-1){
                                /* others value here!!!! --> not Naked Pairs*/
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;
                        }
                    }
                }

                if(possCellValue.size() == possPairsCoordinate.size()){
                    
                    for(int j=0; j<scopeIndices.length; j++){
                        final int indexXComp = scopeIndices[j][COL_INDEX_INDICATOR] ;
                        final int indexYComp = scopeIndices[j][ROW_INDEX_INDICATOR] ;
                        ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                        boolean isValueToEliminateFound = false;
                        for(int k=0; k<possCellValue.size(); k++){
                            if(possCellValueComp.indexOf(possCellValue.get(k)) != -1){
                                /*values Found*/
                                isValueToEliminateFound = true;
                                break;
                            }
                        }

                        if(!this.isInList(possPairsCoordinate, strategyGraph[indexXComp][indexYComp].getCellCoordinate())
                                && isValueToEliminateFound){
                           // Controller.setTextLearnerStepsMsgBox("add Unit in Naked Pairs for cell index = "+indexXComp+" indexYcomp="+indexYComp+" \n");
                            StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                            solvedUnit.copy( strategyGraph[indexXComp][indexYComp], indexXComp, indexYComp);
                            solvedUnit.setLogicalRule(NAKED_PAIRS_INDICATOR);
                            solvedUnit.setScopeEffectiveIn(scope);
                            for(int k=0; k<possCellValue.size(); k++){
                            //    Controller.setTextLearnerStepsMsgBox(" with value to eliminate"+possCellValue.get(k)+"\n");
                                solvedUnit.setImpossValue(possCellValue.get(k));
                            }
                            solvedUnit.setPurposeOfLastLogicalRule(ELIMINATE_INDICATOR);
                            this.stepsMatrix.getBreadthStepsFoundOnRule(NAKED_PAIRS_INDEX).add(solvedUnit);

                            isNakedPairsFound = true;
                        }
                    }
                }
            }
        }
        return isNakedPairsFound;
    }
    public boolean isInList(ArrayList<SudokuCoordinate> list, SudokuCoordinate x){
        for(int i=0; i<list.size(); i++){
            SudokuCoordinate y = list.get(i);
            if(y.getRowIndex()==x.getRowIndex() && y.getColumnIndex()==x.getColumnIndex())
                return true;
        }
        return false;
    }

    /* Hidden Pairs : found the number of set which contain all the digit in certain set */
    public boolean isHiddenPairsFound(){

        final int defaultIndexX = DEFAULT_VALUE;
        final int defaultIndexY = DEFAULT_VALUE;
        boolean isHiddenPairsFoundinRow = false ;
        boolean isHiddenPairsFoundinCol = false ;
        boolean isHiddenPairsFoundinBox = false ;

        /* check if apply in all Column  - take the first cell of all row */
        for( int i= 0 ; i < NUM_CELLS_IN_UNIT; i++){
            final int[][] sameColumnIndices = strategyGraph[i][defaultIndexY].getSameColumnIndices();
            final boolean isApplied = this.isHiddenPairsApplied(sameColumnIndices, COL_SCOPE_INDICATOR);
            isHiddenPairsFoundinCol = isHiddenPairsFoundinCol || isApplied;
        }

        /* check if apply in all row - take the first cell of all column  */
        for( int i=0; i<NUM_CELLS_IN_UNIT ; i++){
            final int[][] sameRowIndices = strategyGraph[defaultIndexX][i].getSameRowIndices();
            final boolean isApplied = this.isHiddenPairsApplied(sameRowIndices, ROW_SCOPE_INDICATOR);
            isHiddenPairsFoundinRow = isHiddenPairsFoundinRow || isApplied;
        }

        /* check if apply in box */
        /* take the first cells in every box for checking */
        for(int i=0; i < NUM_CELLS_IN_UNIT; i+=BOX_LENGTH_IN_CELLS){
            for(int j=0; j<NUM_CELLS_IN_UNIT; j+=BOX_LENGTH_IN_CELLS){
                final int[][] sameBoxIndices = strategyGraph[defaultIndexX][i].getSameBoxIndices();
                final boolean isApplied = this.isHiddenPairsApplied(sameBoxIndices, BOX_SCOPE_INDICATOR);
                isHiddenPairsFoundinBox = isHiddenPairsFoundinBox || isApplied;
            }
        }

        return ( isHiddenPairsFoundinRow || isHiddenPairsFoundinCol || isHiddenPairsFoundinBox );
    }
    public boolean isHiddenPairsApplied(int[][] inputScopeIndices, String inputScope){
        final int[][] scopeIndices = inputScopeIndices;
        final String scope = inputScope;
        boolean isHiddenPairsFound = false ;

        int[] numPossValue = new int [NUM_CELLS_IN_UNIT];
        for(int i=0; i<numPossValue.length; i++){
            numPossValue[i] = 0;
        }

         /* record the number of all poss value  */
         for( int i=0 ; i < scopeIndices.length; i++ ){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValue = strategyGraph[indexX][indexY].getListOfPossibleValues() ;
            for(int j=0; j<possCellValue.size(); j++){
                numPossValue[possCellValue.get(j)-1]++;
            }
         }

        /* Step 1: check if is hidden pairs */
        for( int i=0 ; i < scopeIndices.length; i++ ){
            final int indexX = scopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexY = scopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValue = strategyGraph[indexX][indexY].getListOfPossibleValues() ;
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy( strategyGraph[indexX][indexY].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValue.size()>=2 && possCellValue.size()<=4){
            //if( possCellValue.size()==2){
                for(int j=0; j<scopeIndices.length; j++){

                    final int indexXComp = scopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = scopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                    boolean isPairsCell = true;

                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() > possCellValue.size() && possCellValueComp.size()>1){
                    //if( i!=j && possCellValueComp.size()==2){
                        for(int k=0; k<possCellValue.size(); k++){
                            int valueInvolved = possCellValue.get(k);
                            if(possCellValueComp.indexOf(valueInvolved)==-1){
                                /* does not contain all the poss value */
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;
                        }
                    }
                }

                boolean isCorrectNum= true;
                for(int j=0; j<possCellValue.size(); j++){
                    if(numPossValue[possCellValue.get(j)-1] != possCellValue.size()){
                        isCorrectNum = false;
                    }
                }

                if(isCorrectNum && possCellValue.size() == possPairsCoordinate.size()){

                    for(int j=0; j<possPairsCoordinate.size(); j++){
                        final int indexXComp = possPairsCoordinate.get(j).getColumnIndex();
                        final int indexYComp = possPairsCoordinate.get(j).getRowIndex();
                        ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                        boolean isValueToEliminateFound = false;
                        for(int k=0; k<possCellValueComp.size(); k++){
                            if(possCellValue.indexOf(possCellValueComp.get(k)) == -1){
                                /*values Found*/
                                isValueToEliminateFound = true;
                                break;
                            }
                        }

                        if(this.isInList(possPairsCoordinate, strategyGraph[indexXComp][indexYComp].getCellCoordinate())
                                && isValueToEliminateFound){
                            //Controller.setTextLearnerStepsMsgBox("add Unit in Hidden Pairs for cell index = "+indexXComp+" indexYcomp="+indexYComp+" \n");
                            StrategyGraphUnit solvedUnit = new StrategyGraphUnit();
                            solvedUnit.copy( strategyGraph[indexXComp][indexYComp], indexXComp, indexYComp);
                            solvedUnit.setLogicalRule(HIDDEN_PAIRS_INDICATOR);
                            solvedUnit.setScopeEffectiveIn(scope);
                            for(int k=0; k<possCellValueComp.size(); k++){
                                if(possCellValue.indexOf(possCellValueComp.get(k)) == -1){
                                    //Controller.setTextLearnerStepsMsgBox(" with value to eliminate"+possCellValueComp.get(k)+"\n");
                                    solvedUnit.setImpossValue(possCellValueComp.get(k));
                                }
                            }
                            solvedUnit.setPurposeOfLastLogicalRule(ELIMINATE_INDICATOR);
                            this.stepsMatrix.getBreadthStepsFoundOnRule(HIDDEN_PAIRS_INDEX).add(solvedUnit);

                            isHiddenPairsFound = true;
                        }
                    }
                }
            }
        }
        return isHiddenPairsFound;
    }

    /* Solving procedure */
    /* Single in Group */
    public String getSGSolvingProcedure(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int colIndexValue = solvingUnit.getColumnIndex()+1;
        final int rowIndexValue = solvingUnit.getRowIndex()+1;
        final int boxIndexValue = solvingUnit.getBoxIndex()+1;
        final int cellValue = solvingUnit.getDefiniteValue();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer() ;
        logicalSteps.append("Premise - Since values: ");
        if( effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR) ) {/* logical steps with a column */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("found at Column " + COLUMN_INDEX_ALPHA[colIndexValue] + ".\n") ;
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){/* logical steps with a row */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("found at Row " + rowIndexValue + ".\n") ;
        }
        else if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)) {/* logical steps with a box */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("found at Box " + boxIndexValue + ".\n") ;
        }

        logicalSteps.append("---> By rule {Single in Group} Cell(");
        logicalSteps.append(rowIndexValue + ", ");
        logicalSteps.append(COLUMN_INDEX_ALPHA[colIndexValue]+")");
        logicalSteps.append("is assigned value ");
        logicalSteps.append(cellValue);
        logicalSteps.append(". \n");

        return logicalSteps.toString() ;


    }
    public String getSGSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int colIndexValue = solvingUnit.getColumnIndex()+1;
        final int rowIndexValue = solvingUnit.getRowIndex()+1;
        final int boxIndexValue = solvingUnit.getBoxIndex()+1;
        final int cellValue = solvingUnit.getDefiniteValue();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer() ;
        logicalSteps.append("前提 - 數值: ");
        if( effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR) ) {/* logical steps with a column */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("發現在列" + COLUMN_INDEX_ALPHA[colIndexValue] + ".\n") ;
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){/* logical steps with a row */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("發現在行" + rowIndexValue + ".\n") ;
        }
        else if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)) {/* logical steps with a box */
            for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
                final int checkValue = i+1;
                if( cellValue != checkValue ){
                    logicalSteps.append(checkValue+ " ") ;
                }
            }
            logicalSteps.append("發現在回" + boxIndexValue + ".\n") ;
        }

        logicalSteps.append("---> 根據規則 {唯一候選數法} 格(");
        logicalSteps.append(rowIndexValue + ", ");
        logicalSteps.append(COLUMN_INDEX_ALPHA[colIndexValue]+")");
        logicalSteps.append("的答案是");
        logicalSteps.append(cellValue);
        logicalSteps.append(". \n");

        return logicalSteps.toString() ;


    }
    /* Naked Single */
    public String getNSSolvingProcedure(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final int cellValue = solvingUnit.getDefiniteValue();
        StringBuffer logicalSteps = new StringBuffer() ;
        ArrayList<Integer> potentialValues = new ArrayList() ;

        final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();
        final int[][] sameRowIndices = solvingUnit.getSameRowIndices();
        final int[][] sameBoxIndices = solvingUnit.getSameBoxIndices();

        /* for checking if 8 different value set in the same column */
        for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
            if( cellValue != i+1 ){
                potentialValues.add(i+1) ;
            }
        }

        boolean isAllValuesFound = false ;

        /* the counter of the premise */
        int premiseCounter = 1 ;
        StringBuffer colLogicalSteps = new StringBuffer();
        /* 1. found logical step within a COLUMN */
        boolean isPremiseFoundInCol = false ;
        if( !isAllValuesFound ){
            for( int i=0 ;  i < sameColumnIndices.length ; i++) {
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        colLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInCol = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInCol ){
                logicalSteps.append("Premise" + premiseCounter + " - Since values: ");
                logicalSteps.append(colLogicalSteps);
                logicalSteps.append("found at Column ");
                logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]);
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            /* check if all potential values are found in column */
            /* if yes - no need to proceed on, NO - process chceking in row and box*/
            isAllValuesFound = (potentialValues.size()==0) ;
        }

        /* 2. found logical step within a ROW */
        boolean isPremiseFoundInRow = false ;
        StringBuffer rowLogicalSteps = new StringBuffer();
        if(!isAllValuesFound ){
            for( int i=0; i<sameRowIndices.length; i++ ){
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        rowLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInRow = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInRow ){
                logicalSteps.append("Premise" + premiseCounter + " - Since values: ");
                logicalSteps.append(rowLogicalSteps);
                logicalSteps.append("found at Row ");
                logicalSteps.append(Integer.toString(indexY +1));
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            isAllValuesFound = (potentialValues.size() == 0) ;
        }

        /* 2. found logical step within a ROW */
        boolean isPremiseFoundInBox = false ;
        StringBuffer boxLogicalSteps = new StringBuffer();
        if(!isAllValuesFound ){
            for( int i=0; i<sameBoxIndices.length; i++ ){
                final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        boxLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInBox = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInRow ){
                logicalSteps.append("Premise" + premiseCounter + " - Since values: ");
                logicalSteps.append(boxLogicalSteps);
                logicalSteps.append("found at Box ");
                logicalSteps.append(Integer.toString(boxIndex+1));
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            isAllValuesFound = (potentialValues.size() == 0) ;
        }

        logicalSteps.append("---> By rule {Naked Single} cell(");
        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]+", ");
        logicalSteps.append(Integer.toString(indexY +1)+")");
        logicalSteps.append(" can be assigned value ");
        logicalSteps.append(cellValue);
        logicalSteps.append(".\n");

        return logicalSteps.toString() ;
    }
    public String getNSSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final int cellValue = solvingUnit.getDefiniteValue();
        StringBuffer logicalSteps = new StringBuffer() ;
        ArrayList<Integer> potentialValues = new ArrayList() ;

        final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();
        final int[][] sameRowIndices = solvingUnit.getSameRowIndices();
        final int[][] sameBoxIndices = solvingUnit.getSameBoxIndices();

        /* for checking if 8 different value set in the same column */
        for( int i=0; i<NUM_CELLS_IN_UNIT; i++){
            if( cellValue != i+1 ){
                potentialValues.add(i+1) ;
            }
        }

        boolean isAllValuesFound = false ;

        /* the counter of the premise */
        int premiseCounter = 1 ;
        StringBuffer colLogicalSteps = new StringBuffer();
        /* 1. found logical step within a COLUMN */
        boolean isPremiseFoundInCol = false ;
        if( !isAllValuesFound ){
            for( int i=0 ;  i < sameColumnIndices.length ; i++) {
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        colLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInCol = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInCol ){
                logicalSteps.append("前提 " + premiseCounter + " - 數值 ");
                logicalSteps.append(colLogicalSteps);
                logicalSteps.append("發現在列");
                logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]);
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            /* check if all potential values are found in column */
            /* if yes - no need to proceed on, NO - process chceking in row and box*/
            isAllValuesFound = (potentialValues.size()==0) ;
        }

        /* 2. found logical step within a ROW */
        boolean isPremiseFoundInRow = false ;
        StringBuffer rowLogicalSteps = new StringBuffer();
        if(!isAllValuesFound ){
            for( int i=0; i<sameRowIndices.length; i++ ){
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        rowLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInRow = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInRow ){
                logicalSteps.append("前提 " + premiseCounter + " - 數值 ");
                logicalSteps.append(rowLogicalSteps);
                logicalSteps.append("發現在行");
                logicalSteps.append(Integer.toString(indexY +1));
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            isAllValuesFound = (potentialValues.size() == 0) ;
        }

        /* 2. found logical step within a ROW */
        boolean isPremiseFoundInBox = false ;
        StringBuffer boxLogicalSteps = new StringBuffer();
        if(!isAllValuesFound ){
            for( int i=0; i<sameBoxIndices.length; i++ ){
                final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];
                final int definiteValue = strategyGraph[indexXvalue][indexYvalue].getDefiniteValue();
                boolean isValueFound = false ;
                for( int k=0; (!isValueFound) && (k < potentialValues.size()) ; k++){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                    if( (isCellSolved) && (potentialValues.get(k) == definiteValue) ){
                        boxLogicalSteps .append(definiteValue+" ");
                        potentialValues.remove(k) ;
                        isPremiseFoundInBox = true ;
                    }
                }
            }
            /* make up colLogicalSteps*/
            if( isPremiseFoundInRow ){
                logicalSteps.append("前提 " + premiseCounter + " - 數值 ");
                logicalSteps.append(boxLogicalSteps);
                logicalSteps.append("發現在回");
                logicalSteps.append(Integer.toString(boxIndex+1));
                logicalSteps.append(".\n");
                ++premiseCounter ;
            }
            isAllValuesFound = (potentialValues.size() == 0) ;
        }

        logicalSteps.append("---> 根據規則 {顯式唯一法} 格(");
        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]+", ");
        logicalSteps.append(Integer.toString(indexY +1)+")");
        logicalSteps.append("的答案是");
        logicalSteps.append(cellValue);
        logicalSteps.append(".\n");

        return logicalSteps.toString() ;
    }
    /* Hidden Single */
    public String getHSSolvingProcedure(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndexValue = solvingUnit.getBoxIndex()+1;
        final int cellValue = solvingUnit.getDefiniteValue();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer();

        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){ /*found logical step within a COLUMN*/
            int premiseCounter = 1 ;

            final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();

            for( int i=0 ; i < sameColumnIndices.length; i++){
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append("  Premise " + premiseCounter + "- Even cell(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append(" is UnSolved, ");
                        logicalSteps.append(this.getHSSolvingPremise(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("Premise " + premiseCounter + " - Therefore within Column ");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]);
            logicalSteps.append(" there is only One place to accomdate the value '");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){ /*found logical step within a ROW*/
            int premiseCounter = 1 ;

            final int[][] sameRowIndices = solvingUnit.getSameRowIndices();

            for( int i=0 ; i < sameRowIndices.length; i++){
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append("  Premise " + premiseCounter + "- Even cell(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append(" is UnSolved, ");
                        logicalSteps.append(this.getHSSolvingPremise(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("Premise " + premiseCounter + " - Therefore within Row ");
            logicalSteps.append(Integer.toString(indexY+1));
            logicalSteps.append(" there is only One place to accomdate the value '");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }
        else if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){ /*found logical step within a BOX*/
            int premiseCounter = 1 ;

            final int[][] sameBoxIndices = solvingUnit.getSameBoxIndices();

            for( int i=0 ; i < sameBoxIndices.length; i++){
                final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append("  Premise " + premiseCounter + "- Even cell(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append(" is UnSolved, ");
                        logicalSteps.append(this.getHSSolvingPremise(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("Premise " + premiseCounter + " - Therefore within Box ");
            logicalSteps.append(boxIndexValue);
            logicalSteps.append(" there is only One place to accomdate the value '");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }

        logicalSteps.append("---> By rule {Hidden Single} cell(");
        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]+", ");
        logicalSteps.append(Integer.toString(indexY +1)+")");
        logicalSteps.append(" can be assigned value ");
        logicalSteps.append(cellValue);
        logicalSteps.append(".\n");

        return logicalSteps.toString();
    }
    private String getHSSolvingPremise( int indexX, int indexY, int cellValue ){

        StringBuffer premises = new StringBuffer();
        /* anywhere within the same scope of the Unsolved cell, contains the solved cell with the target cell value */
        boolean isOtherCellFoundSuchValue = false ;

        /* 2-1. check the same column */
        final int[][] sameColumnIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameColumnIndices.length) ; i++){
            final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "within the same Column cell(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append(" cell value is '");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }

        /* 2-2. check the same row */
        final int[][] sameRowIndices = strategyGraph[indexX][indexY].getSameRowIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameRowIndices.length) ; i++){
            final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "within the same Row cell(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append(" cell value is '");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }

        /* 2-3. check the same box */
        final int[][] sameBoxIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameBoxIndices.length) ; i++){
            final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "within the same Box cell(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append(" cell value is '");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }
        return premises.toString() ;
    }
    public String getHSSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit){
        final StrategyGraphUnit solvingUnit = inputSolvingUnit;
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndexValue = solvingUnit.getBoxIndex()+1;
        final int cellValue = solvingUnit.getDefiniteValue();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer();

        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){ /*found logical step within a COLUMN*/
            int premiseCounter = 1 ;

            final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();

            for( int i=0 ; i < sameColumnIndices.length; i++){
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append(" 前提 " + premiseCounter + "- 即使格(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append("是未解決, ");
                        logicalSteps.append(this.getHSSolvingPremiseInChinese(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("前提 " + premiseCounter + " - 因此，在列");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]);
            logicalSteps.append(" 只有一個地方以適應值'");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){ /*found logical step within a ROW*/
            int premiseCounter = 1 ;

            final int[][] sameRowIndices = solvingUnit.getSameRowIndices();

            for( int i=0 ; i < sameRowIndices.length; i++){
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append(" 前提 " + premiseCounter + "- 即使格(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append("是未解決, ");
                        logicalSteps.append(this.getHSSolvingPremiseInChinese(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("前提 " + premiseCounter + " - 因此，在行");
            logicalSteps.append(Integer.toString(indexY+1));
            logicalSteps.append(" 只有一個地方以適應值'");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }
        else if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){ /*found logical step within a BOX*/
            int premiseCounter = 1 ;

            final int[][] sameBoxIndices = solvingUnit.getSameBoxIndices();

            for( int i=0 ; i < sameBoxIndices.length; i++){
                final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                    /* 1.2. for each UnSolved cells, found out the reason why the cellValue cant be put at this Cell */
                    if(!isCellSolved){
                        logicalSteps.append(" 前提 " + premiseCounter + "- 即使格(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexXvalue+1]+", ");
                        logicalSteps.append((indexYvalue+1)+")");
                        logicalSteps.append("是未解決, ");
                        logicalSteps.append(this.getHSSolvingPremiseInChinese(indexXvalue, indexYvalue, cellValue));
                        ++premiseCounter ;
                    }
                }
            }
            logicalSteps.append("前提 " + premiseCounter + " - 因此，在回");
            logicalSteps.append(boxIndexValue);
            logicalSteps.append(" 只有一個地方以適應值");
            logicalSteps.append(cellValue);
            logicalSteps.append("'. \n");
        }

        logicalSteps.append("---> 根據規則 {隱式唯一法} 格(");
        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX +1]+", ");
        logicalSteps.append(Integer.toString(indexY +1)+")");
        logicalSteps.append("的答案是");
        logicalSteps.append(cellValue);
        logicalSteps.append(".\n");

        return logicalSteps.toString();
    }
    private String getHSSolvingPremiseInChinese( int indexX, int indexY, int cellValue ){

        StringBuffer premises = new StringBuffer();
        /* anywhere within the same scope of the Unsolved cell, contains the solved cell with the target cell value */
        boolean isOtherCellFoundSuchValue = false ;

        /* 2-1. check the same column */
        final int[][] sameColumnIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameColumnIndices.length) ; i++){
            final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "在同一列的格(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append("的答案是'");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }

        /* 2-2. check the same row */
        final int[][] sameRowIndices = strategyGraph[indexX][indexY].getSameRowIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameRowIndices.length) ; i++){
            final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "在同一行的格(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append("的答案是'");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }

        /* 2-3. check the same box */
        final int[][] sameBoxIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
        for( int i=0 ; (!isOtherCellFoundSuchValue && i < sameBoxIndices.length) ; i++){
            final int indexXvalue = sameBoxIndices[i][COL_INDEX_INDICATOR];
            final int indexYvalue = sameBoxIndices[i][ROW_INDEX_INDICATOR];

            /* the cell value found */
            boolean isSameAsCheckValue = false;
            if(strategyGraph[indexXvalue][indexYvalue].hasDefiniteValue()){
                if(strategyGraph[indexXvalue][indexYvalue].getDefiniteValue() == cellValue){
                    isSameAsCheckValue = true;
                }
            }

            if(isSameAsCheckValue){
                /* the cell is solved */
                boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                if(isCellSolved) {
                    premises.append( "在同一行的格(");
                    premises.append(COLUMN_INDEX_ALPHA[indexXvalue+1] + ", ");
                    premises.append(Integer.toString(indexYvalue+1)+")");
                    premises.append("的答案是'");
                    premises.append(cellValue);
                    premises.append("'. \n");
                    isOtherCellFoundSuchValue = true ;
                }
            }
        }
        return premises.toString() ;
    }
    /* Intersecton Reduction*/
    public String getIRSolvingProcedure(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
        final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer();

        //final int[] involvedValue = strategyGraph[indexX][indexY].getPossValuesNotIn(solvingUnit);
        final int[] involvedValue = inputValuesInvolved;
        /*get the first value*/

        final int cellValue = involvedValue[0];

        final int UNDEF_FLG = -1 ;
        int effectiveScopeValue = UNDEF_FLG;  /* the effecitve column or row */
        int singleLineBox = UNDEF_FLG ;

        if( effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){

            /* found logical step within a COLUMN */
            int premiseCounter = 1 ;
            final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();
            effectiveScopeValue = indexX;

            /* 1. get the fundation values */
            /* the same scope of unSolved cells */
            // newly added for loop &&  singleLineBox == UNDEF_FLG
            for( int i=0 ; i < sameColumnIndices.length &&  singleLineBox == UNDEF_FLG; ++i){
                /* 1.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    /* check all cells expect the involved cell */
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 1.2 check each UnSolve cells, in boxes other than the cell applied with the logical step */
                    if( (boxIndex != tempBoxIndex) && (singleLineBox == UNDEF_FLG) ){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        singleLineBox = tempBoxIndex;
                        if(!isCellSolved){
                            /* 1.3 find out the box that there is only a single row can accomodate the cell value */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int j=0; j < sameBoxIndices.length ; ++j){
                                final int sameBoxIndexX = sameBoxIndices[i][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[i][ROW_INDEX_INDICATOR];
                                final boolean isPossValue = strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue);
                                if( isPossValue && (effectiveScopeValue != sameBoxIndexX) ){
                                    singleLineBox = UNDEF_FLG;
                                }
                            }
                        }
                    }
                }
            }
            /* 2. make up the premises */
            boolean isPremisesFormed = false ;
            for( int j=0; (!isPremisesFormed && (j<sameColumnIndices.length)); ++j){
                /* 2.1. find out every UnSolved cells within the same row */
                final int indexXvalue = sameColumnIndices[j][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[j][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){/* check all cells expect the involved cell */
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 2.2 find UnSolved cell in the box with single line to accomondate the cell value */
                    if( singleLineBox == tempBoxIndex){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                        if(!isCellSolved) {
                            /* 2.3 check if the cell is in the effective scope (line) */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();

                            for( int k=0 ; k < sameBoxIndices.length ; ++k){
                                final int sameBoxIndexX = sameBoxIndices[k][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[k][ROW_INDEX_INDICATOR];
                                final boolean isSolvedInBox = strategyGraph[sameBoxIndexX][sameBoxIndexY].getDefiniteValueSet();

                                if(!isSolvedInBox){
                                    if( indexX == sameBoxIndexX && strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue)){
                                        logicalSteps.append("Premise " + premiseCounter + " - For Box ");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". Cell(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(") is Possible for cell value ");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    else
                                    {
                                        logicalSteps.append("Premise " + premiseCounter + " - For Box ");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". Cell(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(") is Impossible for cell value ");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    ++premiseCounter ;
                                }
                            }
                        }
                        isPremisesFormed = true ;
                    }
                }
            }
            /* 2.4 Conclusion */
            logicalSteps.append("Premise " + premiseCounter + " - As a result, in Box " );
            logicalSteps.append(Integer.toString(singleLineBox+1)+". The column ");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]);
            logicalSteps.append(" is the only line able for accommodating the value ");
            logicalSteps.append(cellValue);
            logicalSteps.append( ". \n");
            ++premiseCounter ;

            logicalSteps.append("---> By rule {Intersection Reduction} The value ");
            logicalSteps.append(cellValue);
            logicalSteps.append(" can be eliminated from Cell(");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
            logicalSteps.append(Integer.toString(indexY+1)+") ");
            logicalSteps.append( ". \n");
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){ /* 2. found logical step within a ROW */

            int premiseCounter = 1 ;
            final int[][] sameRowIndices = solvingUnit.getSameRowIndices();
            effectiveScopeValue = indexY;

            /* 1. get the box with single line value */
            /* the same scope of unSolved cells */
            for( int i = 0 ; i < sameRowIndices.length && singleLineBox == UNDEF_FLG; i++ ){
                /* 1.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue)) ){
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();

                    /* 1.2 check each UnSolve cells, in boxes other than the cell applied with the logical step */
                    if( (boxIndex != tempBoxIndex) && (singleLineBox == UNDEF_FLG) ){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        if( !isCellSolved ){
                            singleLineBox = tempBoxIndex ;
                            /* 1.3 find out the box that there is only a single row can accomodate the cell value */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int j=0 ; j < sameBoxIndices.length && singleLineBox != UNDEF_FLG; j++){
                                final int sameBoxIndexX = sameBoxIndices[j][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[j][ROW_INDEX_INDICATOR];

                                final boolean isPossValue = strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue);
                                if( isPossValue && (effectiveScopeValue != sameBoxIndexY) ){
                                    singleLineBox = UNDEF_FLG ;
                                   
                                }
                            }
                        }
                    }
                }
            }

            /* 2. make up the premises */
            boolean isPremisesFormed = false ;
            for( int j = 0 ; ( (!isPremisesFormed) && (j < sameRowIndices.length) ) ; ++j){
                /* 2.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameRowIndices[j][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[j][ROW_INDEX_INDICATOR];

                if( !(( indexX == indexXvalue ) && (indexY == indexYvalue )) ){
                    final int tempBoxIndex= strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 2.2 find UnSolved cell in the box with single line to accomondate the cell value */
                    if(singleLineBox == tempBoxIndex){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        if( !isCellSolved ){
                            // 2.3 check if the cell is in the effective scope (line)
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int k=0 ; k < sameBoxIndices.length ; ++k){
                                final int sameBoxIndexX = sameBoxIndices[k][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[k][ROW_INDEX_INDICATOR];
                                final boolean isSolvedInBox = strategyGraph[sameBoxIndexX][sameBoxIndexY].getDefiniteValueSet();
                                if(!isSolvedInBox){
                                    if( indexY == sameBoxIndexY && strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue)){
                                        logicalSteps.append("Premise " + premiseCounter + " - For Box ");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". Cell(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(") is Possible for cell value ");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    else
                                    {
                                        logicalSteps.append("Premise " + premiseCounter + " - For Box ");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". Cell(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(") is Impossible for cell value ");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    ++premiseCounter ;
                                }
                            }
                            isPremisesFormed = true ;
                        }
                    }
                }
            }

            /* 2.4 Conclusion */
            logicalSteps.append("Premise " + premiseCounter + " - As a result, in Box " );
            logicalSteps.append(Integer.toString(singleLineBox+1)+". The row ");
            logicalSteps.append(Integer.toString(indexY+1));
            logicalSteps.append(" is the only line able for accommodating the value ");
            logicalSteps.append(cellValue);
            logicalSteps.append( ". \n");
            ++premiseCounter ;

            logicalSteps.append("---> By rule {Intersection Reduction} The value ");
            logicalSteps.append(cellValue);
            logicalSteps.append(" can be eliminated from Cell(");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
            logicalSteps.append(Integer.toString(indexY+1)+") ");
            logicalSteps.append( ". \n");
        }

        return logicalSteps.toString() ;

    }
    public String getIRSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
        final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        StringBuffer logicalSteps = new StringBuffer();

        //final int[] involvedValue = strategyGraph[indexX][indexY].getPossValuesNotIn(solvingUnit);
        final int[] involvedValue = inputValuesInvolved;
        /*get the first value*/

        final int cellValue = involvedValue[0];

        final int UNDEF_FLG = -1 ;
        int effectiveScopeValue = UNDEF_FLG;  /* the effecitve column or row */
        int singleLineBox = UNDEF_FLG ;

        if( effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){

            /* found logical step within a COLUMN */
            int premiseCounter = 1 ;
            final int[][] sameColumnIndices = solvingUnit.getSameColumnIndices();
            effectiveScopeValue = indexX;

            /* 1. get the fundation values */
            /* the same scope of unSolved cells */
            // newly added for loop &&  singleLineBox == UNDEF_FLG
            for( int i=0 ; i < sameColumnIndices.length &&  singleLineBox == UNDEF_FLG; ++i){
                /* 1.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameColumnIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){
                    /* check all cells expect the involved cell */
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 1.2 check each UnSolve cells, in boxes other than the cell applied with the logical step */
                    if( (boxIndex != tempBoxIndex) && (singleLineBox == UNDEF_FLG) ){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        singleLineBox = tempBoxIndex;
                        if(!isCellSolved){
                            /* 1.3 find out the box that there is only a single row can accomodate the cell value */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int j=0; j < sameBoxIndices.length ; ++j){
                                final int sameBoxIndexX = sameBoxIndices[i][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[i][ROW_INDEX_INDICATOR];
                                final boolean isPossValue = strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue);
                                if( isPossValue && (effectiveScopeValue != sameBoxIndexX) ){
                                    singleLineBox = UNDEF_FLG;
                                }
                            }
                        }
                    }
                }
            }
            /* 2. make up the premises */
            boolean isPremisesFormed = false ;
            for( int j=0; (!isPremisesFormed && (j<sameColumnIndices.length)); ++j){
                /* 2.1. find out every UnSolved cells within the same row */
                final int indexXvalue = sameColumnIndices[j][COL_INDEX_INDICATOR];
                final int indexYvalue = sameColumnIndices[j][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue) ) ){/* check all cells expect the involved cell */
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 2.2 find UnSolved cell in the box with single line to accomondate the cell value */
                    if( singleLineBox == tempBoxIndex){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();

                        if(!isCellSolved) {
                            /* 2.3 check if the cell is in the effective scope (line) */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();

                            for( int k=0 ; k < sameBoxIndices.length ; ++k){
                                final int sameBoxIndexX = sameBoxIndices[k][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[k][ROW_INDEX_INDICATOR];
                                final boolean isSolvedInBox = strategyGraph[sameBoxIndexX][sameBoxIndexY].getDefiniteValueSet();

                                if(!isSolvedInBox){
                                    if( indexX == sameBoxIndexX && strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue)){
                                        logicalSteps.append("前提 " + premiseCounter + " - 在回");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". 格(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(")的值可能是");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    else
                                    {
                                        logicalSteps.append("前提 " + premiseCounter + " - 在回");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". 格(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(")的值不可能是");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    ++premiseCounter ;
                                }
                            }
                        }
                        isPremisesFormed = true ;
                    }
                }
            }
            /* 2.4 Conclusion */
            logicalSteps.append("前提 " + premiseCounter + " - 因此，在回" );
            logicalSteps.append(Integer.toString(singleLineBox+1)+". 列");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]);
            logicalSteps.append(" 是唯一能夠為包容價值 ");
            logicalSteps.append(cellValue);
            logicalSteps.append( "的列. \n");
            ++premiseCounter ;

            logicalSteps.append("---> 根據規則 {區塊刪減法} 數值 ");
            logicalSteps.append(cellValue);
            logicalSteps.append("可以由格((");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
            logicalSteps.append(Integer.toString(indexY+1)+") ");
            logicalSteps.append( "除去. \n");
        }
        else if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){ /* 2. found logical step within a ROW */

            int premiseCounter = 1 ;
            final int[][] sameRowIndices = solvingUnit.getSameRowIndices();
            effectiveScopeValue = indexY;

            /* 1. get the box with single line value */
            /* the same scope of unSolved cells */
            for( int i = 0 ; i < sameRowIndices.length && singleLineBox == UNDEF_FLG; i++ ){
                /* 1.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameRowIndices[i][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[i][ROW_INDEX_INDICATOR];

                if( !( (indexX == indexXvalue) && (indexY == indexYvalue)) ){
                    final int tempBoxIndex = strategyGraph[indexXvalue][indexYvalue].getBoxIndex();

                    /* 1.2 check each UnSolve cells, in boxes other than the cell applied with the logical step */
                    if( (boxIndex != tempBoxIndex) && (singleLineBox == UNDEF_FLG) ){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        if( !isCellSolved ){
                            singleLineBox = tempBoxIndex ;
                            /* 1.3 find out the box that there is only a single row can accomodate the cell value */
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int j=0 ; j < sameBoxIndices.length && singleLineBox != UNDEF_FLG; j++){
                                final int sameBoxIndexX = sameBoxIndices[j][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[j][ROW_INDEX_INDICATOR];

                                final boolean isPossValue = strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue);
                                if( isPossValue && (effectiveScopeValue != sameBoxIndexY) ){
                                    singleLineBox = UNDEF_FLG ;

                                }
                            }
                        }
                    }
                }
            }

            /* 2. make up the premises */
            boolean isPremisesFormed = false ;
            for( int j = 0 ; ( (!isPremisesFormed) && (j < sameRowIndices.length) ) ; ++j){
                /* 2.1. find out every UnSolved cells within the same column */
                final int indexXvalue = sameRowIndices[j][COL_INDEX_INDICATOR];
                final int indexYvalue = sameRowIndices[j][ROW_INDEX_INDICATOR];

                if( !(( indexX == indexXvalue ) && (indexY == indexYvalue )) ){
                    final int tempBoxIndex= strategyGraph[indexXvalue][indexYvalue].getBoxIndex();
                    /* 2.2 find UnSolved cell in the box with single line to accomondate the cell value */
                    if(singleLineBox == tempBoxIndex){
                        boolean isCellSolved = strategyGraph[indexXvalue][indexYvalue].getDefiniteValueSet();
                        if( !isCellSolved ){
                            // 2.3 check if the cell is in the effective scope (line)
                            final int[][] sameBoxIndices = strategyGraph[indexXvalue][indexYvalue].getSameBoxIndices();
                            for( int k=0 ; k < sameBoxIndices.length ; ++k){
                                final int sameBoxIndexX = sameBoxIndices[k][COL_INDEX_INDICATOR];
                                final int sameBoxIndexY = sameBoxIndices[k][ROW_INDEX_INDICATOR];
                                final boolean isSolvedInBox = strategyGraph[sameBoxIndexX][sameBoxIndexY].getDefiniteValueSet();
                                if(!isSolvedInBox){
                                    if( indexY == sameBoxIndexY && strategyGraph[sameBoxIndexX][sameBoxIndexY].isPossibleFor(cellValue)){
                                        logicalSteps.append("前提 " + premiseCounter + " - 在回");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". 格(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(")的值可能是");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    else
                                    {
                                        logicalSteps.append("前提 " + premiseCounter + " - 在回");
                                        logicalSteps.append(Integer.toString(singleLineBox+1)+". 格(");
                                        logicalSteps.append(COLUMN_INDEX_ALPHA[sameBoxIndexX+1]+", ");
                                        logicalSteps.append(Integer.toString(sameBoxIndexY+1));
                                        logicalSteps.append(")的值不可能是");
                                        logicalSteps.append(cellValue);
                                        logicalSteps.append(" \n");
                                    }
                                    ++premiseCounter ;
                                }
                            }
                            isPremisesFormed = true ;
                        }
                    }
                }
            }

            /* 2.4 Conclusion */
            logicalSteps.append("前提 " + premiseCounter + " - 因此，在回" );
            logicalSteps.append(Integer.toString(singleLineBox+1)+". 行");
            logicalSteps.append(Integer.toString(indexY+1));
            logicalSteps.append("是唯一能夠為包容價值");
            logicalSteps.append(cellValue);
            logicalSteps.append("的行. \n");
            ++premiseCounter ;

            logicalSteps.append("---> 根據規則 {區塊刪減法} 數值");
            logicalSteps.append(cellValue);
            logicalSteps.append("可以由格(");
            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
            logicalSteps.append(Integer.toString(indexY+1)+") ");
            logicalSteps.append("除去. \n");
        }

        return logicalSteps.toString() ;

    }

    /* Naked Pairs */
    /* To be improve ... */
    public String getNPSolvingProcedure(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
        final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        final int[] ValuesInvolved = inputValuesInvolved;
        int premiseCounter = 1;

        StringBuffer logicalSteps = new StringBuffer();
        /*logicalSteps.append("indexX = " + indexX+"\n");
        logicalSteps.append("indexY = " + indexY+"\n");
        logicalSteps.append("boxIndex = " + boxIndex+"\n");
        logicalSteps.append("effectiveScope = " + effectiveScope+"\n");
        for(int i =0; i<ValuesInvolved.length; i++){
            logicalSteps.append("ValuesInvolved= " + ValuesInvolved[i]+"\n");
        }*/


        int[][] sameScopeIndices = null;
        String scope = "";
        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
            scope = COL_SCOPE_INDICATOR + " " + COLUMN_INDEX_ALPHA[indexX+1];
        }
        if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameRowIndices();
            scope = ROW_SCOPE_INDICATOR + " " + (indexY+1);
        }
        if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
            scope = BOX_SCOPE_INDICATOR + " " + boxIndex;
        }

        /* Step 1: check if is naked pairs */
        for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXpair = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYpair = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;

            ArrayList<Integer> possCellValue = strategyGraph[indexXpair][indexYpair].getListOfPossibleValues();
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy(strategyGraph[indexXpair][indexYpair].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValue.size()>=2 && possCellValue.size()<=4){
                for(int j=0; j<sameScopeIndices.length; j++){

                    final int indexXComp = sameScopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = sameScopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;

                    boolean isPairsCell = true;
                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() <= possCellValue.size() && possCellValueComp.size()>1){
                        for(int k=0; k<possCellValueComp.size(); k++){
                            int valueInvolved = possCellValueComp.get(k);
                            if(possCellValue.indexOf(valueInvolved)==-1){
                                /* others value here!!!! --> not Naked Pairs*/
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;

                        }
                    }
                }

                boolean isRealPossPair= true;
                if(possCellValue.size() == possPairsCoordinate.size()){
                    /* possible pairs found */
                    /* Step 2 - check if the possible pairs found is the pair of given hints */
                    for(int k=0; k<ValuesInvolved.length; k++){
                        if(possCellValue.indexOf(ValuesInvolved[k])==-1){
                            /* another need to be deleted values found - not this pairs */
                            isRealPossPair = false;
                            break;
                        }
                    }

                    if(isRealPossPair &&
                            !this.isInList(possPairsCoordinate, strategyGraph[indexX][indexY].getCellCoordinate())){

                        // for testing
                        /*logicalSteps.append("real Possible pairs found!the pairs are\n");
                        for(int k=0; k<possPairsCoordinate.size();k++){
                            logicalSteps.append(possPairsCoordinate.get(k).getColumnIndex()
                                    + ", " + possPairsCoordinate.get(k).getRowIndex()+"\n");
                        }*/
                        // process interpretation
                        logicalSteps.append("Premise " + premiseCounter + " - For "+ scope+"\n");
                        premiseCounter++;
                        for(int k=0; k<possPairsCoordinate.size(); k++){
                            logicalSteps.append("Cell(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                            logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") is possible for value(s) ");
                            ArrayList<Integer> cellValue= strategyGraph[possPairsCoordinate.get(k).getColumnIndex()][possPairsCoordinate.get(k).getRowIndex()].getListOfPossibleValues() ;
                            for(int m=0; m<cellValue.size(); m++){
                                logicalSteps.append(Integer.toString(cellValue.get(m)) + " ");
                            }
                            logicalSteps.append("\n");
                        }

                        logicalSteps.append("Premise " + premiseCounter + " - As a result, in " + scope +", values ");
                        for(int k=0; k<possCellValue.size(); k++){
                            logicalSteps.append(Integer.toString(possCellValue.get(k))+" ");
                        }
                        logicalSteps.append("should be accommodated in ");
                        for(int k=0; k<possPairsCoordinate.size(); k++){
                            logicalSteps.append("Cell(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                            logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") ");
                        }

                        logicalSteps.append("\n---> By rule {Naked Pairs} The value ");
                        for(int k=0; k<ValuesInvolved.length; k++){
                            logicalSteps.append(ValuesInvolved[k] + " ");
                        }
                        logicalSteps.append(" can be eliminated from Cell(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
                        logicalSteps.append(Integer.toString(indexY+1)+") ");
                        logicalSteps.append( ". \n");

                        return logicalSteps.toString();

                    }
                }

            }
        }
        return logicalSteps.toString();
    }
    public String getNPSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
        final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        final int[] ValuesInvolved = inputValuesInvolved;
        int premiseCounter = 1;

        StringBuffer logicalSteps = new StringBuffer();
        /*logicalSteps.append("indexX = " + indexX+"\n");
        logicalSteps.append("indexY = " + indexY+"\n");
        logicalSteps.append("boxIndex = " + boxIndex+"\n");
        logicalSteps.append("effectiveScope = " + effectiveScope+"\n");
        for(int i =0; i<ValuesInvolved.length; i++){
            logicalSteps.append("ValuesInvolved= " + ValuesInvolved[i]+"\n");
        }*/


        int[][] sameScopeIndices = null;
        String scope = "";
        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
            scope =  "列" + COLUMN_INDEX_ALPHA[indexX+1];
        }
        if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameRowIndices();
            scope = "行" + (indexY+1);
        }
        if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
            scope = "回" + boxIndex;
        }

        /* Step 1: check if is naked pairs */
        for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXpair = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYpair = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;

            ArrayList<Integer> possCellValue = strategyGraph[indexXpair][indexYpair].getListOfPossibleValues();
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy(strategyGraph[indexXpair][indexYpair].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValue.size()>=2 && possCellValue.size()<=4){
                for(int j=0; j<sameScopeIndices.length; j++){

                    final int indexXComp = sameScopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = sameScopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;

                    boolean isPairsCell = true;
                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() <= possCellValue.size() && possCellValueComp.size()>1){
                        for(int k=0; k<possCellValueComp.size(); k++){
                            int valueInvolved = possCellValueComp.get(k);
                            if(possCellValue.indexOf(valueInvolved)==-1){
                                /* others value here!!!! --> not Naked Pairs*/
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;

                        }
                    }
                }

                boolean isRealPossPair= true;
                if(possCellValue.size() == possPairsCoordinate.size()){
                    /* possible pairs found */
                    /* Step 2 - check if the possible pairs found is the pair of given hints */
                    for(int k=0; k<ValuesInvolved.length; k++){
                        if(possCellValue.indexOf(ValuesInvolved[k])==-1){
                            /* another need to be deleted values found - not this pairs */
                            isRealPossPair = false;
                            break;
                        }
                    }

                    if(isRealPossPair &&
                             !this.isInList(possPairsCoordinate, strategyGraph[indexX][indexY].getCellCoordinate())){
                        // for testing
                        /*logicalSteps.append("real Possible pairs found!the pairs are\n");
                        for(int k=0; k<possPairsCoordinate.size();k++){
                            logicalSteps.append(possPairsCoordinate.get(k).getColumnIndex()
                                    + ", " + possPairsCoordinate.get(k).getRowIndex()+"\n");
                        }*/
                        // process interpretation
                        logicalSteps.append("前提 " + premiseCounter + " - 在 "+ scope+"\n");
                        premiseCounter++;
                        for(int k=0; k<possPairsCoordinate.size(); k++){
                            logicalSteps.append("格(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                            logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+")的值可能是 ");
                            ArrayList<Integer> cellValue= strategyGraph[possPairsCoordinate.get(k).getColumnIndex()][possPairsCoordinate.get(k).getRowIndex()].getListOfPossibleValues() ;
                            for(int m=0; m<cellValue.size(); m++){
                                logicalSteps.append(Integer.toString(cellValue.get(m)) + " ");
                            }
                            logicalSteps.append("\n");
                        }

                        logicalSteps.append("前提 " + premiseCounter + " - 因此，在 " + scope +", 數值 ");
                        for(int k=0; k<possCellValue.size(); k++){
                            logicalSteps.append(Integer.toString(possCellValue.get(k))+" ");
                        }
                        logicalSteps.append(" 一定在");
                        for(int k=0; k<possPairsCoordinate.size(); k++){
                            logicalSteps.append("格(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                            logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") ");
                        }

                        logicalSteps.append("\n---> 根據規則 {顯式數對刪減法} 數值");
                        for(int k=0; k<ValuesInvolved.length; k++){
                            logicalSteps.append(ValuesInvolved[k] + " ");
                        }
                        logicalSteps.append(" 可以由格(");
                        logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
                        logicalSteps.append(Integer.toString(indexY+1)+") ");
                        logicalSteps.append( "除去. \n");

                        return logicalSteps.toString();

                    }
                }

            }
        }
        return logicalSteps.toString();
    }

    /* Hidden Pairs */
    public String getHPSolvingProcedure(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
    final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        final int[] ValuesInvolved = inputValuesInvolved;
        int premiseCounter = 1;

        StringBuffer logicalSteps = new StringBuffer();

        /* Determine the scope */
        int[][] sameScopeIndices = null;
        String scope = "";
        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
            scope = COL_SCOPE_INDICATOR + " " + COLUMN_INDEX_ALPHA[indexX+1];
        }
        if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameRowIndices();
            scope = ROW_SCOPE_INDICATOR + " " + (indexY+1);
        }
        if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
            scope = BOX_SCOPE_INDICATOR + " " + boxIndex;
        }

        int[] numPossValue = new int [NUM_CELLS_IN_UNIT];
        for(int i=0; i<numPossValue.length; i++){
            numPossValue[i] = 0;
        }

         /* record the number of all poss value  */
         for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXcheck = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYcheck = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValueCheck = strategyGraph[indexXcheck][indexYcheck].getListOfPossibleValues() ;
            for(int j=0; j<possCellValueCheck.size(); j++){
                numPossValue[possCellValueCheck.get(j)-1]++;
            }
         }

        /* Step 1: check if is hidden pairs */
        for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXcheck = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYcheck = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValueCheck = strategyGraph[indexXcheck][indexYcheck].getListOfPossibleValues() ;
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy( strategyGraph[indexXcheck][indexYcheck].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValueCheck.size()>=2 && possCellValueCheck.size()<=4){
            //if( possCellValue.size()==2){
                for(int j=0; j<sameScopeIndices.length; j++){

                    final int indexXComp = sameScopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = sameScopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                    boolean isPairsCell = true;

                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() > possCellValueCheck.size() && possCellValueComp.size()>1){
                    //if( i!=j && possCellValueComp.size()==2){
                        for(int k=0; k<possCellValueCheck.size(); k++){
                            int valueInvolved = possCellValueCheck.get(k);
                            if(possCellValueComp.indexOf(valueInvolved)==-1){
                                /* does not contain all the poss value */
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;
                        }
                    }
                }

                boolean isCorrectNum= true;
                for(int j=0; j<possCellValueCheck.size(); j++){
                    if(numPossValue[possCellValueCheck.get(j)-1] != possCellValueCheck.size()){
                        isCorrectNum = false;
                    }
                }

                if(isCorrectNum && possCellValueCheck.size() == possPairsCoordinate.size()){

                    for(int j=0; j<possPairsCoordinate.size(); j++){
                        final int indexXComp = possPairsCoordinate.get(j).getColumnIndex();
                        final int indexYComp = possPairsCoordinate.get(j).getRowIndex();
                        ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                        boolean isValueToEliminateFound = false;
                        ArrayList<Integer> values = new ArrayList<Integer>();
                        for(int k=0; k<possCellValueComp.size(); k++){
                            if(possCellValueCheck.indexOf(possCellValueComp.get(k)) == -1){
                                /*values Found*/
                                values.add(possCellValueComp.get(k));

                                isValueToEliminateFound = true;

                            }
                        }

                        boolean isRealPairs = true;
                        isRealPairs = isRealPairs && (indexX == indexXComp)
                                && (indexY == indexYComp) && (ValuesInvolved.length == values.size());

                        for(int k=0; k<ValuesInvolved.length; k++){
                            if( values.indexOf(ValuesInvolved[k]) == -1 ){
                                isRealPairs = false;
                            }
                        }

                        if(this.isInList(possPairsCoordinate, strategyGraph[indexXComp][indexYComp].getCellCoordinate())
                                && isRealPairs
                                && isValueToEliminateFound){
                            // process interpretation
                            logicalSteps.append("Premise " + premiseCounter + " - For "+ scope+"\n");
                            premiseCounter++;
                            for(int k=0; k<possPairsCoordinate.size(); k++){
                                logicalSteps.append("Cell(");
                                logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                                logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") is possible for value(s) ");
                                ArrayList<Integer> cellValue= strategyGraph[possPairsCoordinate.get(k).getColumnIndex()][possPairsCoordinate.get(k).getRowIndex()].getListOfPossibleValues() ;
                                for(int m=0; m<cellValue.size(); m++){
                                    logicalSteps.append(Integer.toString(cellValue.get(m)) + " ");
                                }
                                logicalSteps.append("\n");
                            }

                            logicalSteps.append("Premise " + premiseCounter + " - As a result, in " + scope +", values ");
                            for(int k=0; k<possCellValueCheck.size(); k++){
                                if(values.indexOf(possCellValueCheck.get(k)) == -1){
                                    logicalSteps.append(Integer.toString(possCellValueCheck.get(k))+" ");
                                }
                            }
                            logicalSteps.append("should be accommodated in ");
                            for(int k=0; k<possPairsCoordinate.size(); k++){
                                logicalSteps.append("Cell(");
                                logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                                logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") ");
                            }

                            logicalSteps.append("\n---> By rule {Hidden Pairs} The value ");
                            for(int k=0; k<ValuesInvolved.length; k++){
                                logicalSteps.append(ValuesInvolved[k] + " ");
                            }
                            logicalSteps.append(" can be eliminated from Cell(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
                            logicalSteps.append(Integer.toString(indexY+1)+") ");
                            logicalSteps.append( ". \n");

                            return logicalSteps.toString();

                        }
                    }
                }
            }
        }
        return logicalSteps.toString();
    }
    public String getHPSolvingProcedureInChinese(StrategyGraphUnit inputSolvingUnit, int[] inputValuesInvolved){
        final StrategyGraphUnit solvingUnit = new StrategyGraphUnit();
        solvingUnit.copy(inputSolvingUnit);
        final int indexX = solvingUnit.getColumnIndex();
        final int indexY = solvingUnit.getRowIndex();
        final int boxIndex = solvingUnit.getBoxIndex();
        final String effectiveScope = solvingUnit.getScopeEffectiveIn();
        final int[] ValuesInvolved = inputValuesInvolved;
        int premiseCounter = 1;

        StringBuffer logicalSteps = new StringBuffer();

        /* Determine the scope */
        int[][] sameScopeIndices = null;
        String scope = "";
        if(effectiveScope.equalsIgnoreCase(COL_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameColumnIndices();
            scope =  "列" + COLUMN_INDEX_ALPHA[indexX+1];
        }
        if(effectiveScope.equalsIgnoreCase(ROW_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameRowIndices();
            scope = "行" + (indexY+1);
        }
        if(effectiveScope.equalsIgnoreCase(BOX_SCOPE_INDICATOR)){
            sameScopeIndices = strategyGraph[indexX][indexY].getSameBoxIndices();
            scope = "回" + boxIndex;
        }
        
        int[] numPossValue = new int [NUM_CELLS_IN_UNIT];
        for(int i=0; i<numPossValue.length; i++){
            numPossValue[i] = 0;
        }

         /* record the number of all poss value  */
         for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXcheck = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYcheck = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValueCheck = strategyGraph[indexXcheck][indexYcheck].getListOfPossibleValues() ;
            for(int j=0; j<possCellValueCheck.size(); j++){
                numPossValue[possCellValueCheck.get(j)-1]++;
            }
         }

        /* Step 1: check if is hidden pairs */
        for( int i=0 ; i < sameScopeIndices.length; i++ ){
            final int indexXcheck = sameScopeIndices[i][COL_INDEX_INDICATOR] ;
            final int indexYcheck = sameScopeIndices[i][ROW_INDEX_INDICATOR] ;
            ArrayList<Integer> possCellValueCheck = strategyGraph[indexXcheck][indexYcheck].getListOfPossibleValues() ;
            ArrayList<SudokuCoordinate> possPairsCoordinate = new ArrayList<SudokuCoordinate>();
            SudokuCoordinate activeCoordinate = new SudokuCoordinate();
            activeCoordinate.copy( strategyGraph[indexXcheck][indexYcheck].getCellCoordinate()) ;
            possPairsCoordinate.add(activeCoordinate) ;

            if( possCellValueCheck.size()>=2 && possCellValueCheck.size()<=4){
            //if( possCellValue.size()==2){
                for(int j=0; j<sameScopeIndices.length; j++){

                    final int indexXComp = sameScopeIndices[j][COL_INDEX_INDICATOR] ;
                    final int indexYComp = sameScopeIndices[j][ROW_INDEX_INDICATOR] ;
                    ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                    boolean isPairsCell = true;

                    /* check if pairs, triple, Quad found */
                    if( i!=j && possCellValueComp.size() > possCellValueCheck.size() && possCellValueComp.size()>1){
                    //if( i!=j && possCellValueComp.size()==2){
                        for(int k=0; k<possCellValueCheck.size(); k++){
                            int valueInvolved = possCellValueCheck.get(k);
                            if(possCellValueComp.indexOf(valueInvolved)==-1){
                                /* does not contain all the poss value */
                                isPairsCell = false;
                                break;
                            }
                        }

                        if(isPairsCell){
                            activeCoordinate = new SudokuCoordinate();
                            activeCoordinate.copy( strategyGraph[indexXComp][indexYComp].getCellCoordinate()) ;
                            possPairsCoordinate.add(activeCoordinate) ;
                        }
                    }
                }

                boolean isCorrectNum= true;
                for(int j=0; j<possCellValueCheck.size(); j++){
                    if(numPossValue[possCellValueCheck.get(j)-1] != possCellValueCheck.size()){
                        isCorrectNum = false;
                    }
                }

                if(isCorrectNum && possCellValueCheck.size() == possPairsCoordinate.size()){

                    for(int j=0; j<possPairsCoordinate.size(); j++){
                        final int indexXComp = possPairsCoordinate.get(j).getColumnIndex();
                        final int indexYComp = possPairsCoordinate.get(j).getRowIndex();
                        ArrayList<Integer> possCellValueComp = strategyGraph[indexXComp][indexYComp].getListOfPossibleValues() ;
                        boolean isValueToEliminateFound = false;
                        ArrayList<Integer> values = new ArrayList<Integer>();
                        for(int k=0; k<possCellValueComp.size(); k++){
                            if(possCellValueCheck.indexOf(possCellValueComp.get(k)) == -1){
                                /*values Found*/
                                values.add(possCellValueComp.get(k));
                                
                                isValueToEliminateFound = true;

                            }
                        }
                        
                        boolean isRealPairs = true;
                        isRealPairs = isRealPairs && (indexX == indexXComp)
                                && (indexY == indexYComp) && (ValuesInvolved.length == values.size());
                        
                        for(int k=0; k<ValuesInvolved.length; k++){
                            if( values.indexOf(ValuesInvolved[k]) == -1 ){
                                isRealPairs = false;
                            }
                        }
                        
                        if(this.isInList(possPairsCoordinate, strategyGraph[indexXComp][indexYComp].getCellCoordinate())
                                && isRealPairs
                                && isValueToEliminateFound){
                            // process interpretation
                            logicalSteps.append("前提 " + premiseCounter + " - 在 "+ scope+"\n");
                            premiseCounter++;
                            for(int k=0; k<possPairsCoordinate.size(); k++){
                                logicalSteps.append("格(");
                                logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                                logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+")的值可能是 ");
                                ArrayList<Integer> cellValue= strategyGraph[possPairsCoordinate.get(k).getColumnIndex()][possPairsCoordinate.get(k).getRowIndex()].getListOfPossibleValues() ;
                                for(int m=0; m<cellValue.size(); m++){
                                    logicalSteps.append(Integer.toString(cellValue.get(m)) + " ");
                                }
                                logicalSteps.append("\n");
                            }

                            logicalSteps.append("前提 " + premiseCounter + " - 因此，在 " + scope +", 數值 ");
                            for(int k=0; k<possCellValueCheck.size(); k++){
                                if(values.indexOf(possCellValueCheck.get(k)) == -1){
                                    logicalSteps.append(Integer.toString(possCellValueCheck.get(k))+" ");
                                }
                            }
                            logicalSteps.append("一定在 ");
                            for(int k=0; k<possPairsCoordinate.size(); k++){
                                logicalSteps.append("格(");
                                logicalSteps.append(COLUMN_INDEX_ALPHA[possPairsCoordinate.get(k).getColumnIndex()+1]+", ");
                                logicalSteps.append(Integer.toString(possPairsCoordinate.get(k).getRowIndex()+1)+") ");
                            }

                            logicalSteps.append("\n---> 根據規則 {隱性數對刪減法} 數值 ");
                            for(int k=0; k<ValuesInvolved.length; k++){
                                logicalSteps.append(ValuesInvolved[k] + " ");
                            }
                            logicalSteps.append(" 可以由格(");
                            logicalSteps.append(COLUMN_INDEX_ALPHA[indexX+1]+", ");
                            logicalSteps.append(Integer.toString(indexY+1)+") ");
                            logicalSteps.append( "除去. \n");

                            return logicalSteps.toString();

                        }
                    }
                }
            }
        }
        return logicalSteps.toString();
    }

    private boolean isPuzzleSolved(){
        boolean isPuzzleSolved = true;
        for(int i=0; i<this.strategyGraph.length && isPuzzleSolved; i++){
            for(int j=0; j<this.strategyGraph[i].length; j++){
                /* cannot use hasDefiniteValue function, as some definite value is define by elimination without set */
                if(!this.strategyGraph[i][j].getDefiniteValueSet()){
                    isPuzzleSolved = false;
                    break;
                }
            }
        }
        return isPuzzleSolved;
    }

    // testing
    //public StrategyGraphUnit[][] solvePuzzle(){return this.strategyGraph;}
    public StrategyGraphUnit[][] solvePuzzle(){
        // 20091017 phrase2 start- comment
        // this method need to improved after skills matrix and steps matrix are interpreted
        //CellValuePossibilityUnit[][] solvedPuzzle;
        //CellValuePossibilityUnit[][] tempPuzzle = strategyGraph;
        // 20071017 phrase2 end
        /*for(int i=0; i<rulesRanking.size(); i++){
            Controller.setTextLearnerStepsMsgBox("\n"+i+" "+LOGICAL_RULES[rulesRanking.get(i)]);
        }*/
        /* empty the StepsMatrix*/
        this.empthDepthStepsMatrix();
        this.emptyBreadthStepsMatrix();
        while(!this.isPuzzleSolved()){
            this.applyLogicalRules();
            // 20091019 phrase2 start - change all  breadthSteps to Skills Matrix
            for(int i=0; i<this.stepsMatrix.getBreadthStepsLength(); i++){
                for(int j=0; j<this.stepsMatrix.getBreadthStepsFoundOnRule(i).size(); j++){
                    final int indexX = this.stepsMatrix.getBreadthStepsFoundOnRule(i ).get(j).getColumnIndex();
                    final int indexY = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getRowIndex();
                    final int definiteValue = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getDefiniteValue();
                    final String logicalRule = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getLogicalRule();
                    final String effectiveScope = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getScopeEffectiveIn();
                    final String purposeOfApplied = this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getPurposeOfLastLogicalRule();

                    //Controller.setTextLearnerStepsMsgBox("depth Step : " + indexX+" "+ indexY+" "+ definiteValue+" "+logicalRule+"\n");
                    
                    if(this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getPurposeOfLastLogicalRule().equalsIgnoreCase(DEFINE_INDICATOR)){
                        if(!this.strategyGraph[indexX][indexY].getDefiniteValueSet()
                                || this.strategyGraph[indexX][indexY].getLogicalRule().equalsIgnoreCase(UNKNOWN)){
                         /* Testing */
                         //Controller.setTextCellsValueLabel(indexX, indexY, definiteValue);
                         //Controller.setTextLearnerStepsMsgBox(indexX+" "+ indexY+" "+ definiteValue+" "+logicalRule+"\n");
                         //Controller.setTextLearnerStepsMsgBox("depth Step : " + indexX+" "+ indexY+" "+ definiteValue+" "+logicalRule+"\n");
                            this.setCellDefiniteValue(indexX, indexY, definiteValue, logicalRule, effectiveScope, purposeOfApplied);
                            // 20091029 phrase2 start
                            /* Store the stepsMatric for tracking user performance */
                            if(!this.strategyGraph[indexX][indexY].getLogicalRule().equalsIgnoreCase(UNKNOWN)){
                                this.addARule(indexX, indexY, logicalRule);
                            }else{
                                this.setRuleUsed(indexX, indexY, logicalRule);
                            }
                            this.stepsMatrix.addDepthSteps(strategyGraph[indexX][indexY]);
                            // 20091029 phrase2 end
                        }else{
                            this.addARule(indexX, indexY, logicalRule);
                        }
                    }else if(this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j).getPurposeOfLastLogicalRule().equalsIgnoreCase(ELIMINATE_INDICATOR)){
                        //Controller.setTextLearnerStepsMsgBox("reach here !!~~ elimin scope!! "+logicalRule+"\n");
                        int[] impossValue = Controller.getInvolvedValue(this.stepsMatrix.getBreadthStepsFoundOnRule(i).get(j));
                        for(int k=0; k<impossValue.length; k++){
                          //  Controller.setTextLearnerStepsMsgBox("values Involved = " + impossValue[k]);
                            this.setImpossValue(indexX, indexY, impossValue[k]);
                        }
                    }
                }
            }
        }
        return this.strategyGraph;
    }

    // 20091029 phrase2 start
    public void recordStepsMatrix(int stepCount){
        this.stepsMatrix.recordStepsMatrix(stepCount);
    }
    public ArrayList<StrategyGraphUnit> getStepsDepthMatrix(){
        return this.stepsMatrix.getDepthStepsMatrix();
    }
    public void setStepsDepthMatrix(ArrayList<StrategyGraphUnit> inputDepthSteps){
        stepsMatrix.setDepthStepsMatrix(inputDepthSteps);
    }
    public void recordSkillsMatrix(){
        stepsMatrix.recordSkillsMatrix();
    }
    // testing
    public StrategyGraphUnit getStrategyUnit(int indexX, int indexY){
        return this.strategyGraph[indexX][indexY];
    }
    // 20091029 phrase2 end

    /* local variables */
    private String gameDifficulty;
    private int numGivenCells;
    /* cell possibility */
    private StrategyGraphUnit[][] strategyGraph;
    /* number of definite value in row, column and box*/
    private int[] numDefiniteValueInRow;
    private int[] numDefiniteValueInCol;
    private int[] numDefiniteValueInBox;
    /* store the rules found  */
    /* -each array indicate the logicalrules */
    /* -each arraylist store the unit that rules applied on*/
    private StepsMatrix stepsMatrix;

    //20091017 phrase2 start
    /* rules priority ranking - information are added in order */
    //private ArrayList<Integer> rulesRanking;
    // 20091017 phrase2 end

    /* constant variables */
    /* BasicSudokuParam */
    final static int NUM_CELLS_IN_UNIT = BasicSudokuParam.getNumCellsInUnit();
    final static int BOX_LENGTH_IN_CELLS = BasicSudokuParam.getBoxLengthInCells();
    /* SudokuGameInfoParam */
    final static String[] LOGICAL_RULES = SudokuGameInfoParam.getLogicalRules();
    final static String[] DIFFICULTY_LEVEL = SudokuGameInfoParam.getDifficultyLevels();
    final static String[] COLUMN_INDEX_ALPHA = SudokuGameInfoParam.getColumnIndexAlpha();
    /* ExpertModelProperties */
    final static String NOT_APPLICABLE_INDICATOR = ExpertModelProperties.getNotApplicableIndicator();
    final static String SINGLE_IN_GROUP_INDICATOR = ExpertModelProperties.getSingleInGroupIndicator();
    final static int SINGLE_IN_GROUP_INDEX = ExpertModelProperties.getSingleInGroupIndex();
    final static String HIDDEN_SINGLE_INDICATOR = ExpertModelProperties.getHiddenSingleIndicator();
    final static int HIDDEN_SINGLE_INDEX = ExpertModelProperties.getHiddenSingleIndex();
    final static String NAKED_SINGLE_INDICATOR = ExpertModelProperties.getNakedSingleIndicator();
    final static int NAKED_SINGLE_INDEX = ExpertModelProperties.getNakedSingleIndex();
    final static String INTERSECT_REDUCT_INDICATOR = ExpertModelProperties.getIntersectReductIndicator();
    final static int INTERSECT_REDUCT_INDEX = ExpertModelProperties.getIntersectReductIndex();
    final static String HIDDEN_PAIRS_INDICATOR = ExpertModelProperties.getHiddenPairsIndicator();
    final static int HIDDEN_PAIRS_INDEX = ExpertModelProperties.getHiddenPairsIndex();
    final static String NAKED_PAIRS_INDICATOR = ExpertModelProperties.getNakedPairsIndicator();
    final static int NAKED_PAIRS_INDEX = ExpertModelProperties.getNakedPairsIndex();
    final static String ROW_SCOPE_INDICATOR = ExpertModelProperties.getRowScopeIndicator();
    final static String COL_SCOPE_INDICATOR = ExpertModelProperties.getColScopeIndicator();
    final static String BOX_SCOPE_INDICATOR = ExpertModelProperties.getBoxScopeIndicator();
    final static String ALL_SCOPE_INDICATOR = ExpertModelProperties.getAllScopeIndicator();
    final static String DEFINE_INDICATOR = ExpertModelProperties.getDefineIndicator();
    final static String ELIMINATE_INDICATOR = ExpertModelProperties.getEliminateIndicator();
    final static int ROW_INDEX_INDICATOR = ExpertModelProperties.getRowIndexIndicator();
    final static int COL_INDEX_INDICATOR = ExpertModelProperties.getColIndexIndicator();
    final static int BOX_INDEX_INDICATOR = ExpertModelProperties.getBoxIndexIndicator();
    /* Only for this class */
    final static String UNKNOWN = "UN" ;
    final static int DEFAULT_VALUE = 0 ;
    final static int INACTIVE_FLAG = -1;
    /* Minimum and Maximun number of possible coordinates wirhin a box */
    final static int MIN_POSS_COR_IR = 1;
    final static int MAX_POSS_COR_IR = 4;
    /* SudokuComponentsProperties */
    final String HINTS_PANEL_SEPARATOR = SudokuComponentsProperties.getHintsPanelSeparator();

    // for testing;
    ControlLayer Controller;


}
